Add a "Shared with me" section.

This commit is contained in:
Jimmy Shih
2013-02-05 10:58:49 -08:00
parent b5fa77a98d
commit 69f2b18f10
5 changed files with 220 additions and 18 deletions
+25
View File
@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright 2013 Google Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/track_list_header"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:paddingBottom="2dp"
android:paddingLeft="5dp"
android:paddingTop="2dp"
android:text="@string/track_list_shared_with_me"
style="?android:attr/listSeparatorTextViewStyle" />
+6 -1
View File
@@ -2424,7 +2424,12 @@ limitations under the License.
success.">
Now recording a new track.
</string>
<string name="track_list_shared_with_me"
translation_description="The section header for &#8216;Shared with me&#8217; tracks from Google
Drive.">
Shared with me
</string>
<!-- Track Widget -->
<string name="track_widget_config_title"
translation_description="Title of the page to configure the My Tracks widget items.">
@@ -0,0 +1,168 @@
/*
* Copyright 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.android.apps.mytracks;
import com.google.android.apps.mytracks.content.TracksColumns;
import com.google.android.maps.mytracks.R;
import android.content.Context;
import android.database.Cursor;
import android.database.DataSetObserver;
import android.support.v4.widget.ResourceCursorAdapter;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
/**
* A section based resource cursor adapter. Currently only supports one
* additional section header, "Shared with me".
*
* @author Jimmy Shih
*/
public abstract class SectionResourceCursorAdapter extends ResourceCursorAdapter {
private enum ItemType {
TRACK, HEADER
}
private final LayoutInflater layoutInflater;
private int sharedWithMeIndex = -1;
public SectionResourceCursorAdapter(Context context, int layout, Cursor cursor, int flags) {
super(context, layout, cursor, flags);
this.layoutInflater = LayoutInflater.from(context);
if (cursor != null) {
sharedWithMeIndex = getSharedWithMeIndex();
cursor.registerDataSetObserver(dataSetObserver);
}
}
private DataSetObserver dataSetObserver = new DataSetObserver() {
@Override
public void onChanged() {
sharedWithMeIndex = getSharedWithMeIndex();
};
@Override
public void onInvalidated() {
sharedWithMeIndex = -1;
};
};
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (getItemViewType(position) == ItemType.TRACK.ordinal()) {
return super.getView(getCursorPosition(position), convertView, parent);
} else {
TextView textView;
if (convertView == null) {
textView = (TextView) layoutInflater.inflate(R.layout.track_list_header, parent, false);
} else {
textView = (TextView) convertView;
}
return textView;
}
}
@Override
public int getViewTypeCount() {
return ItemType.values().length;
}
@Override
public int getCount() {
int count = super.getCount();
return count != 0 && sharedWithMeIndex != -1 ? count + 1 : count;
}
@Override
public boolean isEnabled(int position) {
return getItemViewType(position) == ItemType.TRACK.ordinal();
}
@Override
public Object getItem(int position) {
if (getItemViewType(position) == ItemType.TRACK.ordinal()) {
return super.getItem(getCursorPosition(position));
}
return null;
}
@Override
public long getItemId(int position) {
if (getItemViewType(position) == ItemType.TRACK.ordinal()) {
return super.getItemId(getCursorPosition(position));
}
return -1L;
}
@Override
public int getItemViewType(int position) {
if (sharedWithMeIndex != -1 && sharedWithMeIndex == position) {
return ItemType.HEADER.ordinal();
}
return ItemType.TRACK.ordinal();
}
@Override
public Cursor swapCursor(Cursor newCursor) {
if (getCursor() != null) {
getCursor().unregisterDataSetObserver(dataSetObserver);
}
Cursor oldCursor = super.swapCursor(newCursor);
if (newCursor != null) {
sharedWithMeIndex = getSharedWithMeIndex();
newCursor.registerDataSetObserver(dataSetObserver);
}
return oldCursor;
}
/**
* Gets the Shared with me header index.
*/
private int getSharedWithMeIndex() {
int i = 0;
Cursor cursor = getCursor();
if (cursor != null && cursor.moveToFirst()) {
int index = cursor.getColumnIndex(TracksColumns.SHAREDWITHME);
do {
int sharedWithMe = cursor.getInt(index);
if (sharedWithMe == 1) {
// Returns the index where sharedWithMe == 1
return i;
}
i++;
} while (cursor.moveToNext());
}
return -1;
}
/**
* Gets the underlying cursor position.
*
* @param position the requested position
*/
private int getCursorPosition(int position) {
if (sharedWithMeIndex != -1 && position > sharedWithMeIndex) {
return position - 1;
}
return position;
}
}
@@ -66,7 +66,6 @@ import android.support.v4.app.FragmentActivity;
import android.support.v4.app.LoaderManager.LoaderCallbacks;
import android.support.v4.content.CursorLoader;
import android.support.v4.content.Loader;
import android.support.v4.widget.ResourceCursorAdapter;
import android.util.Log;
import android.view.ContextMenu;
import android.view.ContextMenu.ContextMenuInfo;
@@ -97,7 +96,8 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
private static final int GOOGLE_PLAY_SERVICES_REQUEST_CODE = 0;
private static final String[] PROJECTION = new String[] { TracksColumns._ID, TracksColumns.NAME,
TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME,
TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON };
TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON,
TracksColumns.SHAREDWITHME};
// Callback when the trackRecordingServiceConnection binding changes.
private final Runnable bindChangedCallback = new Runnable() {
@@ -180,7 +180,7 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
boolean isRecording = recordingTrackId
!= PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
updateMenuItems(isRecording);
resourceCursorAdapter.notifyDataSetChanged();
sectionResourceCursorAdapter.notifyDataSetChanged();
trackController.update(isRecording, recordingTrackPaused);
}
});
@@ -333,7 +333,7 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
private TrackRecordingServiceConnection trackRecordingServiceConnection;
private TrackController trackController;
private ListView listView;
private ResourceCursorAdapter resourceCursorAdapter;
private SectionResourceCursorAdapter sectionResourceCursorAdapter;
private TrackDataHub trackDataHub;
// Preferences
@@ -379,7 +379,7 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
startActivity(intent);
}
});
resourceCursorAdapter = new ResourceCursorAdapter(this, R.layout.list_item, null, 0) {
sectionResourceCursorAdapter = new SectionResourceCursorAdapter(this, R.layout.list_item, null, 0) {
@Override
public void bindView(View view, Context context, Cursor cursor) {
int idIndex = cursor.getColumnIndex(TracksColumns._ID);
@@ -406,7 +406,7 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
totalDistance, startTimeDisplay, cursor.getString(descriptionIndex));
}
};
listView.setAdapter(resourceCursorAdapter);
listView.setAdapter(sectionResourceCursorAdapter);
ApiAdapterFactory.getApiAdapter()
.configureListViewContextualMenu(this, listView, contextualActionModeCallback);
@@ -414,17 +414,17 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
@Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
return new CursorLoader(TrackListActivity.this, TracksColumns.CONTENT_URI, PROJECTION, null,
null, TracksColumns._ID + " DESC");
null, TracksColumns.SHAREDWITHME + " ASC, " + TracksColumns._ID + " DESC");
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
resourceCursorAdapter.swapCursor(cursor);
sectionResourceCursorAdapter.swapCursor(cursor);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
resourceCursorAdapter.swapCursor(null);
sectionResourceCursorAdapter.swapCursor(null);
}
});
trackDataHub = TrackDataHub.newInstance(this);
@@ -462,7 +462,7 @@ public class TrackListActivity extends FragmentActivity implements DeleteOneTrac
// Update UI
boolean isRecording = recordingTrackId != PreferencesUtils.RECORDING_TRACK_ID_DEFAULT;
updateMenuItems(isRecording);
resourceCursorAdapter.notifyDataSetChanged();
sectionResourceCursorAdapter.notifyDataSetChanged();
trackController.update(isRecording, recordingTrackPaused);
}
@@ -161,14 +161,18 @@ public class SyncAdapter extends AbstractThreadedSyncAdapter {
context, R.string.drive_deleted_list_key, PreferencesUtils.DRIVE_DELETED_LIST_DEFAULT);
String deletedIds[] = TextUtils.split(driveDeletedList, ";");
for (String id : deletedIds) {
File driveFile = drive.files().get(id).execute();
if (SyncUtils.isInFolder(driveFile, folderId)) {
if (!driveFile.getLabels().getTrashed()) {
drive.files().trash(id).execute();
try {
File driveFile = drive.files().get(id).execute();
if (SyncUtils.isInFolder(driveFile, folderId)) {
if (!driveFile.getLabels().getTrashed()) {
drive.files().trash(id).execute();
}
// if trashed, ignore
} else if (SyncUtils.isSharedWithMe(driveFile)) {
drive.files().delete(id).execute();
}
// if trashed, ignore
} else if (SyncUtils.isSharedWithMe(driveFile)) {
drive.files().delete(id).execute();
} catch (IOException e) {
// safe to ignore
}
}
PreferencesUtils.setString(