summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBobby Georgescu <georgescu@google.com>2013-03-13 21:30:18 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-03-13 21:30:19 +0000
commit7e57c641c1a53ce20b2194e2375e63412d6d14d0 (patch)
tree2c252645f231574bd3220834a0e26827d2afc69b
parente0ebb91d3b5a740f04ec0d1339bd21a769e1a5c6 (diff)
parente2bc54a09412790da5ac7d19c52b964e49e14c25 (diff)
downloadandroid_packages_apps_Snap-7e57c641c1a53ce20b2194e2375e63412d6d14d0.tar.gz
android_packages_apps_Snap-7e57c641c1a53ce20b2194e2375e63412d6d14d0.tar.bz2
android_packages_apps_Snap-7e57c641c1a53ce20b2194e2375e63412d6d14d0.zip
Merge "Sharing support for albums, bulk operations infrastructure" into gb-ub-photos-bryce
-rw-r--r--src/com/android/photos/AlbumSetFragment.java126
-rw-r--r--src/com/android/photos/GalleryActivity.java20
-rw-r--r--src/com/android/photos/MultiChoiceManager.java190
-rw-r--r--src/com/android/photos/PhotoSetFragment.java139
-rw-r--r--src/com/android/photos/SelectionManager.java54
-rw-r--r--src/com/android/photos/adapters/AlbumSetCursorAdapter.java89
-rw-r--r--src/com/android/photos/data/AlbumSetLoader.java7
-rw-r--r--src/com/android/photos/data/PhotoSetLoader.java17
-rw-r--r--src/com/android/photos/shims/LoaderCompatShim.java5
-rw-r--r--src/com/android/photos/shims/MediaItemsLoader.java37
-rw-r--r--src/com/android/photos/shims/MediaSetLoader.java48
11 files changed, 534 insertions, 198 deletions
diff --git a/src/com/android/photos/AlbumSetFragment.java b/src/com/android/photos/AlbumSetFragment.java
index 0d4fcc023..d0bc81fd6 100644
--- a/src/com/android/photos/AlbumSetFragment.java
+++ b/src/com/android/photos/AlbumSetFragment.java
@@ -21,42 +21,54 @@ import android.app.LoaderManager.LoaderCallbacks;
import android.content.Context;
import android.content.Loader;
import android.database.Cursor;
-import android.graphics.drawable.Drawable;
+import android.net.Uri;
import android.os.Bundle;
-import android.text.format.DateFormat;
+import android.provider.MediaStore.Files.FileColumns;
+import android.util.SparseBooleanArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
-import android.widget.CursorAdapter;
import android.widget.GridView;
-import android.widget.ImageView;
-import android.widget.ProgressBar;
-import android.widget.TextView;
import android.widget.Toast;
import com.android.gallery3d.R;
+import com.android.photos.adapters.AlbumSetCursorAdapter;
import com.android.photos.data.AlbumSetLoader;
import com.android.photos.shims.LoaderCompatShim;
import com.android.photos.shims.MediaSetLoader;
-import java.util.Date;
+import java.util.ArrayList;
public class AlbumSetFragment extends Fragment implements OnItemClickListener,
- LoaderCallbacks<Cursor> {
+ LoaderCallbacks<Cursor>, MultiChoiceManager.Delegate, SelectionManager.Client {
private GridView mAlbumSetView;
private View mEmptyView;
private AlbumSetCursorAdapter mAdapter;
+ private LoaderCompatShim<Cursor> mLoaderCompatShim;
+ private MultiChoiceManager mMultiChoiceManager;
+ private SelectionManager mSelectionManager;
private static final int LOADER_ALBUMSET = 1;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- mAdapter = new AlbumSetCursorAdapter(getActivity());
+ Context context = getActivity();
+ mAdapter = new AlbumSetCursorAdapter(context);
+ mMultiChoiceManager = new MultiChoiceManager(context, this);
+ mMultiChoiceManager.setSelectionManager(mSelectionManager);
+ }
+
+ @Override
+ public void setSelectionManager(SelectionManager manager) {
+ mSelectionManager = manager;
+ if (mMultiChoiceManager != null) {
+ mMultiChoiceManager.setSelectionManager(manager);
+ }
}
@Override
@@ -67,6 +79,8 @@ public class AlbumSetFragment extends Fragment implements OnItemClickListener,
mEmptyView = root.findViewById(android.R.id.empty);
mEmptyView.setVisibility(View.GONE);
mAlbumSetView.setAdapter(mAdapter);
+ mAlbumSetView.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE_MODAL);
+ mAlbumSetView.setMultiChoiceModeListener(mMultiChoiceManager);
mAlbumSetView.setOnItemClickListener(this);
getLoaderManager().initLoader(LOADER_ALBUMSET, null, this);
updateEmptyStatus();
@@ -78,6 +92,7 @@ public class AlbumSetFragment extends Fragment implements OnItemClickListener,
// TODO: Switch to AlbumSetLoader
MediaSetLoader loader = new MediaSetLoader(getActivity());
mAdapter.setDrawableFactory(loader);
+ mLoaderCompatShim = loader;
return loader;
}
@@ -100,63 +115,54 @@ public class AlbumSetFragment extends Fragment implements OnItemClickListener,
@Override
public void onItemClick(AdapterView<?> av, View v, int pos, long id) {
- Cursor c = (Cursor) av.getItemAtPosition(pos);
- int albumId = c.getInt(AlbumSetLoader.INDEX_ID);
- // TODO launch an activity showing the photos in the album
- Toast.makeText(v.getContext(), "Clicked " + albumId, Toast.LENGTH_SHORT).show();
+ if (mLoaderCompatShim == null) {
+ // Not fully initialized yet, discard
+ return;
+ }
+ Cursor item = (Cursor) mAdapter.getItem(pos);
+ Toast.makeText(v.getContext(),
+ "Tapped " + item.getInt(AlbumSetLoader.INDEX_ID),
+ Toast.LENGTH_SHORT).show();
}
- private static class AlbumSetCursorAdapter extends CursorAdapter {
+ @Override
+ public int getItemMediaType(Object item) {
+ return FileColumns.MEDIA_TYPE_NONE;
+ }
- private LoaderCompatShim<Cursor> mDrawableFactory;
+ @Override
+ public int getItemSupportedOperations(Object item) {
+ return ((Cursor) item).getInt(AlbumSetLoader.INDEX_SUPPORTED_OPERATIONS);
+ }
- public void setDrawableFactory(LoaderCompatShim<Cursor> factory) {
- mDrawableFactory = factory;
- }
- private Date mDate = new Date(); // Used for converting timestamps for display
+ @Override
+ public Object getItemAtPosition(int position) {
+ return mAdapter.getItem(position);
+ }
- public AlbumSetCursorAdapter(Context context) {
- super(context, null, false);
- }
+ @Override
+ public ArrayList<Uri> getSubItemUrisForItem(Object item) {
+ return mLoaderCompatShim.urisForSubItems((Cursor) item);
+ }
- @Override
- public void bindView(View v, Context context, Cursor cursor) {
- TextView titleTextView = (TextView) v.findViewById(
- R.id.album_set_item_title);
- titleTextView.setText(cursor.getString(AlbumSetLoader.INDEX_TITLE));
-
- TextView dateTextView = (TextView) v.findViewById(
- R.id.album_set_item_date);
- long timestamp = cursor.getLong(AlbumSetLoader.INDEX_TIMESTAMP);
- if (timestamp > 0) {
- mDate.setTime(timestamp);
- dateTextView.setText(DateFormat.getMediumDateFormat(context).format(mDate));
- } else {
- dateTextView.setText(null);
- }
-
- ProgressBar uploadProgressBar = (ProgressBar) v.findViewById(
- R.id.album_set_item_upload_progress);
- if (cursor.getInt(AlbumSetLoader.INDEX_COUNT_PENDING_UPLOAD) > 0) {
- uploadProgressBar.setVisibility(View.VISIBLE);
- uploadProgressBar.setProgress(50);
- } else {
- uploadProgressBar.setVisibility(View.INVISIBLE);
- }
-
- ImageView thumbImageView = (ImageView) v.findViewById(
- R.id.album_set_item_image);
- Drawable recycle = thumbImageView.getDrawable();
- Drawable drawable = mDrawableFactory.drawableForItem(cursor, recycle);
- if (recycle != drawable) {
- thumbImageView.setImageDrawable(drawable);
- }
- }
+ @Override
+ public Object getPathForItemAtPosition(int position) {
+ return mLoaderCompatShim.getPathForItem((Cursor) mAdapter.getItem(position));
+ }
- @Override
- public View newView(Context context, Cursor cursor, ViewGroup parent) {
- return LayoutInflater.from(context).inflate(
- R.layout.album_set_item, parent, false);
- }
+ @Override
+ public void deleteItemWithPath(Object itemPath) {
+ mLoaderCompatShim.deleteItemWithPath(itemPath);
}
+
+ @Override
+ public SparseBooleanArray getSelectedItemPositions() {
+ return mAlbumSetView.getCheckedItemPositions();
+ }
+
+ @Override
+ public int getSelectedItemCount() {
+ return mAlbumSetView.getCheckedItemCount();
+ }
+
}
diff --git a/src/com/android/photos/GalleryActivity.java b/src/com/android/photos/GalleryActivity.java
index 420fc3d51..ddf04e365 100644
--- a/src/com/android/photos/GalleryActivity.java
+++ b/src/com/android/photos/GalleryActivity.java
@@ -43,7 +43,7 @@ public class GalleryActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
-
+ mSelectionManager = new SelectionManager(this);
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.viewpager);
setContentView(mViewPager);
@@ -70,13 +70,6 @@ public class GalleryActivity extends Activity {
outState.putInt("tab", getActionBar().getSelectedNavigationIndex());
}
- protected SelectionManager getSelectionManager() {
- if (mSelectionManager == null) {
- mSelectionManager = new SelectionManager(this);
- }
- return mSelectionManager;
- }
-
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.gallery, menu);
@@ -99,7 +92,7 @@ public class GalleryActivity extends Activity {
public static class TabsAdapter extends FragmentPagerAdapter implements
ActionBar.TabListener, ViewPager.OnPageChangeListener {
- private final Context mContext;
+ private final GalleryActivity mActivity;
private final ActionBar mActionBar;
private final ViewPager mViewPager;
private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();
@@ -115,9 +108,9 @@ public class GalleryActivity extends Activity {
}
}
- public TabsAdapter(Activity activity, ViewPager pager) {
+ public TabsAdapter(GalleryActivity activity, ViewPager pager) {
super(activity.getFragmentManager());
- mContext = activity;
+ mActivity = activity;
mActionBar = activity.getActionBar();
mViewPager = pager;
mViewPager.setAdapter(this);
@@ -141,8 +134,11 @@ public class GalleryActivity extends Activity {
@Override
public Fragment getItem(int position) {
TabInfo info = mTabs.get(position);
- return Fragment.instantiate(mContext, info.clss.getName(),
+ Fragment item = Fragment.instantiate(mActivity, info.clss.getName(),
info.args);
+ ((SelectionManager.Client) item).setSelectionManager(
+ mActivity.mSelectionManager);
+ return item;
}
@Override
diff --git a/src/com/android/photos/MultiChoiceManager.java b/src/com/android/photos/MultiChoiceManager.java
new file mode 100644
index 000000000..e00c842fe
--- /dev/null
+++ b/src/com/android/photos/MultiChoiceManager.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.android.photos;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.AsyncTask;
+import android.util.SparseBooleanArray;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.widget.AbsListView.MultiChoiceModeListener;
+import android.widget.ShareActionProvider;
+import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.data.MediaObject;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MultiChoiceManager implements MultiChoiceModeListener,
+ OnShareTargetSelectedListener, SelectionManager.SelectedUriSource {
+
+ public interface Delegate {
+ public SparseBooleanArray getSelectedItemPositions();
+ public int getSelectedItemCount();
+ public int getItemMediaType(Object item);
+ public int getItemSupportedOperations(Object item);
+ public ArrayList<Uri> getSubItemUrisForItem(Object item);
+ public Object getItemAtPosition(int position);
+ public Object getPathForItemAtPosition(int position);
+ public void deleteItemWithPath(Object itemPath);
+ }
+
+ private SelectionManager mSelectionManager;
+ private ShareActionProvider mShareActionProvider;
+ private ActionMode mActionMode;
+ private int numSubItemsCollected = 0;
+ private Context mContext;
+ private Delegate mDelegate;
+
+ private ArrayList<Uri> mSelectedUrisArray = new ArrayList<Uri>();
+
+ public MultiChoiceManager(Context context, Delegate delegate) {
+ mContext = context;
+ mDelegate = delegate;
+ }
+
+ public void setSelectionManager(SelectionManager selectionManager) {
+ mSelectionManager = selectionManager;
+ }
+
+ @Override
+ public ArrayList<Uri> getSelectedShareableUris() {
+ return mSelectedUrisArray;
+ }
+
+ private void updateSelectedTitle(ActionMode mode) {
+ int count = mDelegate.getSelectedItemCount();
+ mode.setTitle(mContext.getResources().getQuantityString(
+ R.plurals.number_of_items_selected, count, count));
+ }
+
+ @Override
+ public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
+ boolean checked) {
+ updateSelectedTitle(mode);
+ Object item = mDelegate.getItemAtPosition(position);
+
+ ArrayList<Uri> subItems = mDelegate.getSubItemUrisForItem(item);
+ if (checked) {
+ mSelectedUrisArray.addAll(subItems);
+ numSubItemsCollected += subItems.size();
+ } else {
+ mSelectedUrisArray.removeAll(subItems);
+ numSubItemsCollected -= subItems.size();
+ }
+
+ mSelectionManager.onItemSelectedStateChanged(mShareActionProvider,
+ mDelegate.getItemMediaType(item),
+ mDelegate.getItemSupportedOperations(item),
+ checked);
+ updateActionItemVisibilities(mode.getMenu(),
+ mSelectionManager.getSupportedOperations());
+ }
+
+ private void updateActionItemVisibilities(Menu menu, int supportedOperations) {
+ MenuItem shareItem = menu.findItem(R.id.menu_share);
+ MenuItem deleteItem = menu.findItem(R.id.menu_delete);
+ shareItem.setVisible((supportedOperations & MediaObject.SUPPORT_SHARE) > 0);
+ deleteItem.setVisible((supportedOperations & MediaObject.SUPPORT_DELETE) > 0);
+ }
+
+ @Override
+ public boolean onCreateActionMode(ActionMode mode, Menu menu) {
+ mSelectionManager.setSelectedUriSource(this);
+ mActionMode = mode;
+ MenuInflater inflater = mode.getMenuInflater();
+ inflater.inflate(R.menu.gallery_multiselect, menu);
+ MenuItem menuItem = menu.findItem(R.id.menu_share);
+ mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
+ mShareActionProvider.setOnShareTargetSelectedListener(this);
+ updateSelectedTitle(mode);
+ return true;
+ }
+
+ @Override
+ public void onDestroyActionMode(ActionMode mode) {
+ // onDestroyActionMode gets called when the share target was selected,
+ // but apparently before the ArrayList is serialized in the intent
+ // so we can't clear the old one here.
+ mSelectedUrisArray = new ArrayList<Uri>();
+ mSelectionManager.onClearSelection();
+ mSelectionManager.setSelectedUriSource(null);
+ mShareActionProvider = null;
+ mActionMode = null;
+ }
+
+ @Override
+ public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
+ updateSelectedTitle(mode);
+ return false;
+ }
+
+ @Override
+ public boolean onShareTargetSelected(ShareActionProvider provider, Intent intent) {
+ mActionMode.finish();
+ return false;
+ }
+
+ private static class BulkDeleteTask extends AsyncTask<Void, Void, Void> {
+ private Delegate mDelegate;
+ private List<Object> mPaths;
+
+ public BulkDeleteTask(Delegate delegate, List<Object> paths) {
+ mDelegate = delegate;
+ mPaths = paths;
+ }
+
+ @Override
+ protected Void doInBackground(Void... ignored) {
+ for (Object path : mPaths) {
+ mDelegate.deleteItemWithPath(path);
+ }
+ return null;
+ }
+ }
+
+ @Override
+ public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.menu_delete:
+ BulkDeleteTask deleteTask = new BulkDeleteTask(mDelegate,
+ getPathsForSelectedItems());
+ deleteTask.execute();
+ mode.finish();
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private List<Object> getPathsForSelectedItems() {
+ List<Object> paths = new ArrayList<Object>();
+ SparseBooleanArray selected = mDelegate.getSelectedItemPositions();
+ for (int i = 0; i < selected.size(); i++) {
+ if (selected.valueAt(i)) {
+ paths.add(mDelegate.getPathForItemAtPosition(i));
+ }
+ }
+ return paths;
+ }
+}
diff --git a/src/com/android/photos/PhotoSetFragment.java b/src/com/android/photos/PhotoSetFragment.java
index 25d80360d..b485cd051 100644
--- a/src/com/android/photos/PhotoSetFragment.java
+++ b/src/com/android/photos/PhotoSetFragment.java
@@ -18,41 +18,31 @@ package com.android.photos;
import android.app.Fragment;
import android.app.LoaderManager.LoaderCallbacks;
+import android.content.Context;
import android.content.Intent;
import android.content.Loader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.util.SparseBooleanArray;
-import android.view.ActionMode;
import android.view.LayoutInflater;
-import android.view.Menu;
-import android.view.MenuInflater;
-import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.GridView;
-import android.widget.ShareActionProvider;
-import android.widget.ShareActionProvider.OnShareTargetSelectedListener;
import com.android.gallery3d.R;
import com.android.gallery3d.app.Gallery;
-import com.android.gallery3d.data.MediaItem;
import com.android.photos.adapters.PhotoThumbnailAdapter;
import com.android.photos.data.PhotoSetLoader;
import com.android.photos.shims.LoaderCompatShim;
import com.android.photos.shims.MediaItemsLoader;
import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-public class PhotoSetFragment extends Fragment implements LoaderCallbacks<Cursor>,
- OnItemClickListener, SelectionManager.SelectedUriSource, MultiChoiceModeListener,
- OnShareTargetSelectedListener {
+public class PhotoSetFragment extends Fragment implements OnItemClickListener,
+ LoaderCallbacks<Cursor>, MultiChoiceManager.Delegate, SelectionManager.Client {
private static final int LOADER_PHOTOSET = 1;
@@ -62,14 +52,24 @@ public class PhotoSetFragment extends Fragment implements LoaderCallbacks<Cursor
private boolean mInitialLoadComplete = false;
private LoaderCompatShim<Cursor> mLoaderCompatShim;
private PhotoThumbnailAdapter mAdapter;
+ private MultiChoiceManager mMultiChoiceManager;
private SelectionManager mSelectionManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- GalleryActivity activity = (GalleryActivity) getActivity();
- mSelectionManager = activity.getSelectionManager();
- mAdapter = new PhotoThumbnailAdapter(activity);
+ Context context = getActivity();
+ mAdapter = new PhotoThumbnailAdapter(context);
+ mMultiChoiceManager = new MultiChoiceManager(context, this);
+ mMultiChoiceManager.setSelectionManager(mSelectionManager);
+ }
+
+ @Override
+ public void setSelectionManager(SelectionManager manager) {
+ mSelectionManager = manager;
+ if (mMultiChoiceManager != null) {
+ mMultiChoiceManager.setSelectionManager(manager);
+ }
}
@Override
@@ -84,7 +84,7 @@ public class PhotoSetFragment extends Fragment implements LoaderCallbacks<Cursor
mEmptyView.setVisibility(View.GONE);
mPhotoSetView.setAdapter(mAdapter);
mPhotoSetView.setChoiceMode(GridView.CHOICE_MODE_MULTIPLE_MODAL);
- mPhotoSetView.setMultiChoiceModeListener(this);
+ mPhotoSetView.setMultiChoiceModeListener(mMultiChoiceManager);
getLoaderManager().initLoader(LOADER_PHOTOSET, null, this);
updateEmptyStatus();
return root;
@@ -129,112 +129,51 @@ public class PhotoSetFragment extends Fragment implements LoaderCallbacks<Cursor
updateEmptyStatus();
}
- private Set<Uri> mSelectedUris = new HashSet<Uri>();
- private ArrayList<Uri> mSelectedUrisArray = new ArrayList<Uri>();
-
@Override
- public ArrayList<Uri> getSelectedShareableUris() {
- mSelectedUrisArray.clear();
- mSelectedUrisArray.addAll(mSelectedUris);
- return mSelectedUrisArray;
- }
-
- public ArrayList<Uri> getSelectedShareableUrisUncached() {
- mSelectedUrisArray.clear();
- SparseBooleanArray selected = mPhotoSetView.getCheckedItemPositions();
-
- for (int i = 0; i < selected.size(); i++) {
- if (selected.valueAt(i)) {
- Cursor item = mAdapter.getItem(selected.keyAt(i));
- int supported = item.getInt(PhotoSetLoader.INDEX_SUPPORTED_OPERATIONS);
- if ((supported & MediaItem.SUPPORT_SHARE) > 0) {
- mSelectedUrisArray.add(mLoaderCompatShim.uriForItem(item));
- }
- }
- }
-
- return mSelectedUrisArray;
+ public void onLoaderReset(Loader<Cursor> loader) {
}
@Override
- public void onLoaderReset(Loader<Cursor> loader) {
+ public int getItemMediaType(Object item) {
+ return ((Cursor) item).getInt(PhotoSetLoader.INDEX_MEDIA_TYPE);
}
-
- private ShareActionProvider mShareActionProvider;
- private ActionMode mActionMode;
- private boolean mSharePending = false;
-
- private void updateSelectedTitle(ActionMode mode) {
- int count = mPhotoSetView.getCheckedItemCount();
- mode.setTitle(getResources().getQuantityString(
- R.plurals.number_of_items_selected, count, count));
+ @Override
+ public int getItemSupportedOperations(Object item) {
+ return ((Cursor) item).getInt(PhotoSetLoader.INDEX_SUPPORTED_OPERATIONS);
}
@Override
- public void onItemCheckedStateChanged(ActionMode mode, int position, long id,
- boolean checked) {
- updateSelectedTitle(mode);
- Cursor item = mAdapter.getItem(position);
-
- if (checked) {
- mSelectedUris.add(mLoaderCompatShim.uriForItem(item));
- } else {
- mSelectedUris.remove(mLoaderCompatShim.uriForItem(item));
- }
-
- mSelectionManager.onItemSelectedStateChanged(mShareActionProvider,
- item.getInt(PhotoSetLoader.INDEX_MEDIA_TYPE),
- item.getInt(PhotoSetLoader.INDEX_SUPPORTED_OPERATIONS),
- checked);
+ public Object getItemAtPosition(int position) {
+ return mAdapter.getItem(position);
}
+ private ArrayList<Uri> mSubItemUriTemp = new ArrayList<Uri>(1);
@Override
- public boolean onCreateActionMode(ActionMode mode, Menu menu) {
- mSelectionManager.setSelectedUriSource(PhotoSetFragment.this);
- mActionMode = mode;
- MenuInflater inflater = mode.getMenuInflater();
- inflater.inflate(R.menu.gallery_multiselect, menu);
- MenuItem menuItem = menu.findItem(R.id.menu_share);
- mShareActionProvider = (ShareActionProvider) menuItem.getActionProvider();
- mShareActionProvider.setOnShareTargetSelectedListener(this);
- updateSelectedTitle(mode);
- return true;
+ public ArrayList<Uri> getSubItemUrisForItem(Object item) {
+ mSubItemUriTemp.clear();
+ mSubItemUriTemp.add(mLoaderCompatShim.uriForItem((Cursor) item));
+ return mSubItemUriTemp;
}
+
@Override
- public void onDestroyActionMode(ActionMode mode) {
- mSelectedUris.clear();
- if (mSharePending) {
- // onDestroyActionMode gets called when the share target was selected,
- // but apparently before the ArrayList is serialized in the intent
- // so we can't clear the old one here.
- mSelectedUrisArray = new ArrayList<Uri>();
- mSharePending = false;
- } else {
- mSelectedUrisArray.clear();
- }
- mSelectionManager.onClearSelection();
- mSelectionManager.setSelectedUriSource(null);
- mShareActionProvider = null;
- mActionMode = null;
+ public Object getPathForItemAtPosition(int position) {
+ return mLoaderCompatShim.getPathForItem(mAdapter.getItem(position));
}
@Override
- public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
- updateSelectedTitle(mode);
- return false;
+ public void deleteItemWithPath(Object itemPath) {
+ mLoaderCompatShim.deleteItemWithPath(itemPath);
}
@Override
- public boolean onShareTargetSelected(ShareActionProvider provider, Intent intent) {
- mSharePending = true;
- mActionMode.finish();
- return false;
+ public SparseBooleanArray getSelectedItemPositions() {
+ return mPhotoSetView.getCheckedItemPositions();
}
@Override
- public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- return false;
+ public int getSelectedItemCount() {
+ return mPhotoSetView.getCheckedItemCount();
}
}
diff --git a/src/com/android/photos/SelectionManager.java b/src/com/android/photos/SelectionManager.java
index 979dcc7da..ce340c731 100644
--- a/src/com/android/photos/SelectionManager.java
+++ b/src/com/android/photos/SelectionManager.java
@@ -26,7 +26,7 @@ import android.provider.MediaStore.Files.FileColumns;
import android.widget.ShareActionProvider;
import com.android.gallery3d.common.ApiHelper;
-import com.android.gallery3d.data.MediaItem;
+import com.android.gallery3d.data.MediaObject;
import com.android.gallery3d.util.GalleryUtils;
import java.util.ArrayList;
@@ -41,6 +41,10 @@ public class SelectionManager {
public ArrayList<Uri> getSelectedShareableUris();
}
+ public interface Client {
+ public void setSelectionManager(SelectionManager manager);
+ }
+
public SelectionManager(Activity activity) {
mActivity = activity;
if (ApiHelper.AT_LEAST_16) {
@@ -76,10 +80,10 @@ public class SelectionManager {
mSelectedTotalCount += increment;
mCachedShareableUris = null;
- if ((itemSupportedOperations & MediaItem.SUPPORT_DELETE) > 0) {
+ if ((itemSupportedOperations & MediaObject.SUPPORT_DELETE) > 0) {
mSelectedDeletableCount += increment;
}
- if ((itemSupportedOperations & MediaItem.SUPPORT_SHARE) > 0) {
+ if ((itemSupportedOperations & MediaObject.SUPPORT_SHARE) > 0) {
mSelectedShareableCount += increment;
if (itemType == FileColumns.MEDIA_TYPE_IMAGE) {
mSelectedShareableImageCount += increment;
@@ -93,24 +97,42 @@ public class SelectionManager {
mShareIntent.setAction(null).setType(null);
} else if (mSelectedShareableCount >= 1) {
mCachedShareableUris = mUriSource.getSelectedShareableUris();
- if (mSelectedShareableImageCount == mSelectedShareableCount) {
- mShareIntent.setType(GalleryUtils.MIME_TYPE_IMAGE);
- } else if (mSelectedShareableVideoCount == mSelectedShareableCount) {
- mShareIntent.setType(GalleryUtils.MIME_TYPE_VIDEO);
- } else {
- mShareIntent.setType(GalleryUtils.MIME_TYPE_ALL);
- }
- if (mSelectedShareableCount == 1) {
- mShareIntent.setAction(Intent.ACTION_SEND);
- mShareIntent.putExtra(Intent.EXTRA_STREAM, mCachedShareableUris.get(0));
+ if (mCachedShareableUris.size() == 0) {
+ mShareIntent.setAction(null).setType(null);
} else {
- mShareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
- mShareIntent.putExtra(Intent.EXTRA_STREAM, mCachedShareableUris);
+ if (mSelectedShareableImageCount == mSelectedShareableCount) {
+ mShareIntent.setType(GalleryUtils.MIME_TYPE_IMAGE);
+ } else if (mSelectedShareableVideoCount == mSelectedShareableCount) {
+ mShareIntent.setType(GalleryUtils.MIME_TYPE_VIDEO);
+ } else {
+ mShareIntent.setType(GalleryUtils.MIME_TYPE_ALL);
+ }
+ if (mCachedShareableUris.size() == 1) {
+ mShareIntent.setAction(Intent.ACTION_SEND);
+ mShareIntent.putExtra(Intent.EXTRA_STREAM, mCachedShareableUris.get(0));
+ } else {
+ mShareIntent.setAction(Intent.ACTION_SEND_MULTIPLE);
+ mShareIntent.putExtra(Intent.EXTRA_STREAM, mCachedShareableUris);
+ }
}
}
share.setShareIntent(mShareIntent);
- // TODO update deletability, editability, etc.
+ // TODO update editability, etc.
+ }
+
+ public int getSupportedOperations() {
+ if (mSelectedTotalCount == 0) {
+ return 0;
+ }
+ int supported = 0;
+ if (mSelectedDeletableCount == mSelectedTotalCount) {
+ supported |= MediaObject.SUPPORT_DELETE;
+ }
+ if (mSelectedShareableCount > 0) {
+ supported |= MediaObject.SUPPORT_SHARE;
+ }
+ return supported;
}
public void onClearSelection() {
diff --git a/src/com/android/photos/adapters/AlbumSetCursorAdapter.java b/src/com/android/photos/adapters/AlbumSetCursorAdapter.java
new file mode 100644
index 000000000..c387f8f47
--- /dev/null
+++ b/src/com/android/photos/adapters/AlbumSetCursorAdapter.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * 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.android.photos.adapters;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.graphics.drawable.Drawable;
+import android.text.format.DateFormat;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.CursorAdapter;
+import android.widget.ImageView;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+import com.android.gallery3d.R;
+import com.android.photos.data.AlbumSetLoader;
+import com.android.photos.shims.LoaderCompatShim;
+
+import java.util.Date;
+
+public class AlbumSetCursorAdapter extends CursorAdapter {
+
+ private LoaderCompatShim<Cursor> mDrawableFactory;
+
+ public void setDrawableFactory(LoaderCompatShim<Cursor> factory) {
+ mDrawableFactory = factory;
+ }
+ private Date mDate = new Date(); // Used for converting timestamps for display
+
+ public AlbumSetCursorAdapter(Context context) {
+ super(context, null, false);
+ }
+
+ @Override
+ public void bindView(View v, Context context, Cursor cursor) {
+ TextView titleTextView = (TextView) v.findViewById(
+ R.id.album_set_item_title);
+ titleTextView.setText(cursor.getString(AlbumSetLoader.INDEX_TITLE));
+
+ TextView dateTextView = (TextView) v.findViewById(
+ R.id.album_set_item_date);
+ long timestamp = cursor.getLong(AlbumSetLoader.INDEX_TIMESTAMP);
+ if (timestamp > 0) {
+ mDate.setTime(timestamp);
+ dateTextView.setText(DateFormat.getMediumDateFormat(context).format(mDate));
+ } else {
+ dateTextView.setText(null);
+ }
+
+ ProgressBar uploadProgressBar = (ProgressBar) v.findViewById(
+ R.id.album_set_item_upload_progress);
+ if (cursor.getInt(AlbumSetLoader.INDEX_COUNT_PENDING_UPLOAD) > 0) {
+ uploadProgressBar.setVisibility(View.VISIBLE);
+ uploadProgressBar.setProgress(50);
+ } else {
+ uploadProgressBar.setVisibility(View.INVISIBLE);
+ }
+
+ ImageView thumbImageView = (ImageView) v.findViewById(
+ R.id.album_set_item_image);
+ Drawable recycle = thumbImageView.getDrawable();
+ Drawable drawable = mDrawableFactory.drawableForItem(cursor, recycle);
+ if (recycle != drawable) {
+ thumbImageView.setImageDrawable(drawable);
+ }
+ }
+
+ @Override
+ public View newView(Context context, Cursor cursor, ViewGroup parent) {
+ return LayoutInflater.from(context).inflate(
+ R.layout.album_set_item, parent, false);
+ }
+}
diff --git a/src/com/android/photos/data/AlbumSetLoader.java b/src/com/android/photos/data/AlbumSetLoader.java
index b2b5204e6..940473255 100644
--- a/src/com/android/photos/data/AlbumSetLoader.java
+++ b/src/com/android/photos/data/AlbumSetLoader.java
@@ -12,6 +12,7 @@ public class AlbumSetLoader {
public static final int INDEX_THUMBNAIL_HEIGHT = 5;
public static final int INDEX_COUNT_PENDING_UPLOAD = 6;
public static final int INDEX_COUNT = 7;
+ public static final int INDEX_SUPPORTED_OPERATIONS = 8;
public static final String[] PROJECTION = {
"_id",
@@ -21,7 +22,8 @@ public class AlbumSetLoader {
"thumb_width",
"thumb_height",
"count_pending_upload",
- "_count"
+ "_count",
+ "supported_operations"
};
public static final MatrixCursor MOCK = createRandomCursor(30);
@@ -44,7 +46,8 @@ public class AlbumSetLoader {
0,
0,
(random < .3 ? 1 : 0),
- 1
+ 1,
+ 0
};
return row;
}
diff --git a/src/com/android/photos/data/PhotoSetLoader.java b/src/com/android/photos/data/PhotoSetLoader.java
index 72c8e93cc..56c82c4a9 100644
--- a/src/com/android/photos/data/PhotoSetLoader.java
+++ b/src/com/android/photos/data/PhotoSetLoader.java
@@ -29,6 +29,8 @@ import android.provider.MediaStore.Files.FileColumns;
import com.android.photos.drawables.DataUriThumbnailDrawable;
import com.android.photos.shims.LoaderCompatShim;
+import java.util.ArrayList;
+
public class PhotoSetLoader extends CursorLoader implements LoaderCompatShim<Cursor> {
public static final String SUPPORTED_OPERATIONS = "supported_operations";
@@ -95,4 +97,19 @@ public class PhotoSetLoader extends CursorLoader implements LoaderCompatShim<Cur
public Uri uriForItem(Cursor item) {
return null;
}
+
+ @Override
+ public ArrayList<Uri> urisForSubItems(Cursor item) {
+ return null;
+ }
+
+ @Override
+ public void deleteItemWithPath(Object path) {
+
+ }
+
+ @Override
+ public Object getPathForItem(Cursor item) {
+ return null;
+ }
}
diff --git a/src/com/android/photos/shims/LoaderCompatShim.java b/src/com/android/photos/shims/LoaderCompatShim.java
index 9da4436aa..d5bf710de 100644
--- a/src/com/android/photos/shims/LoaderCompatShim.java
+++ b/src/com/android/photos/shims/LoaderCompatShim.java
@@ -19,8 +19,13 @@ package com.android.photos.shims;
import android.graphics.drawable.Drawable;
import android.net.Uri;
+import java.util.ArrayList;
+
public interface LoaderCompatShim<T> {
Drawable drawableForItem(T item, Drawable recycle);
Uri uriForItem(T item);
+ ArrayList<Uri> urisForSubItems(T item);
+ void deleteItemWithPath(Object path);
+ Object getPathForItem(T item);
}
diff --git a/src/com/android/photos/shims/MediaItemsLoader.java b/src/com/android/photos/shims/MediaItemsLoader.java
index fa41c8ec8..d75823404 100644
--- a/src/com/android/photos/shims/MediaItemsLoader.java
+++ b/src/com/android/photos/shims/MediaItemsLoader.java
@@ -28,12 +28,16 @@ import android.util.SparseArray;
import com.android.gallery3d.data.ContentListener;
import com.android.gallery3d.data.DataManager;
import com.android.gallery3d.data.MediaItem;
+import com.android.gallery3d.data.MediaObject;
import com.android.gallery3d.data.MediaSet;
import com.android.gallery3d.data.MediaSet.ItemConsumer;
import com.android.gallery3d.data.MediaSet.SyncListener;
+import com.android.gallery3d.data.Path;
import com.android.gallery3d.util.Future;
import com.android.photos.data.PhotoSetLoader;
+import java.util.ArrayList;
+
/**
* Returns all MediaItems in a MediaSet, wrapping them in a cursor to appear
* like a PhotoSetLoader
@@ -47,6 +51,7 @@ public class MediaItemsLoader extends AsyncTaskLoader<Cursor> implements LoaderC
};
private final MediaSet mMediaSet;
+ private final DataManager mDataManager;
private Future<Integer> mSyncTask = null;
private ContentListener mObserver = new ContentListener() {
@Override
@@ -58,14 +63,15 @@ public class MediaItemsLoader extends AsyncTaskLoader<Cursor> implements LoaderC
public MediaItemsLoader(Context context) {
super(context);
- DataManager dm = DataManager.from(context);
- String path = dm.getTopSetPath(DataManager.INCLUDE_ALL);
- mMediaSet = dm.getMediaSet(path);
+ mDataManager = DataManager.from(context);
+ String path = mDataManager.getTopSetPath(DataManager.INCLUDE_ALL);
+ mMediaSet = mDataManager.getMediaSet(path);
}
public MediaItemsLoader(Context context, String parentPath) {
super(context);
- mMediaSet = DataManager.from(getContext()).getMediaSet(parentPath);
+ mDataManager = DataManager.from(getContext());
+ mMediaSet = mDataManager.getMediaSet(parentPath);
}
@Override
@@ -157,4 +163,27 @@ public class MediaItemsLoader extends AsyncTaskLoader<Cursor> implements LoaderC
return mi == null ? null : mi.getContentUri();
}
+ @Override
+ public ArrayList<Uri> urisForSubItems(Cursor item) {
+ return null;
+ }
+
+ @Override
+ public void deleteItemWithPath(Object path) {
+ MediaObject o = mDataManager.getMediaObject((Path) path);
+ if (o != null) {
+ o.delete();
+ }
+ }
+
+ @Override
+ public Object getPathForItem(Cursor item) {
+ int index = item.getInt(PhotoSetLoader.INDEX_ID);
+ MediaItem mi = mMediaItems.get(index);
+ if (mi != null) {
+ return mi.getPath();
+ }
+ return null;
+ }
+
}
diff --git a/src/com/android/photos/shims/MediaSetLoader.java b/src/com/android/photos/shims/MediaSetLoader.java
index 96c7485bb..d200807f9 100644
--- a/src/com/android/photos/shims/MediaSetLoader.java
+++ b/src/com/android/photos/shims/MediaSetLoader.java
@@ -26,7 +26,9 @@ import android.net.Uri;
import com.android.gallery3d.data.ContentListener;
import com.android.gallery3d.data.DataManager;
import com.android.gallery3d.data.MediaItem;
+import com.android.gallery3d.data.MediaObject;
import com.android.gallery3d.data.MediaSet;
+import com.android.gallery3d.data.Path;
import com.android.gallery3d.data.MediaSet.SyncListener;
import com.android.gallery3d.util.Future;
import com.android.photos.data.AlbumSetLoader;
@@ -46,6 +48,7 @@ public class MediaSetLoader extends AsyncTaskLoader<Cursor> implements LoaderCom
};
private final MediaSet mMediaSet;
+ private final DataManager mDataManager;
private Future<Integer> mSyncTask = null;
private ContentListener mObserver = new ContentListener() {
@Override
@@ -58,14 +61,15 @@ public class MediaSetLoader extends AsyncTaskLoader<Cursor> implements LoaderCom
public MediaSetLoader(Context context) {
super(context);
- DataManager dm = DataManager.from(context);
- String path = dm.getTopSetPath(DataManager.INCLUDE_ALL);
- mMediaSet = dm.getMediaSet(path);
+ mDataManager = DataManager.from(context);
+ String path = mDataManager.getTopSetPath(DataManager.INCLUDE_ALL);
+ mMediaSet = mDataManager.getMediaSet(path);
}
public MediaSetLoader(Context context, String path) {
super(context);
- mMediaSet = DataManager.from(getContext()).getMediaSet(path);
+ mDataManager = DataManager.from(getContext());
+ mMediaSet = mDataManager.getMediaSet(path);
}
@Override
@@ -111,6 +115,7 @@ public class MediaSetLoader extends AsyncTaskLoader<Cursor> implements LoaderCom
row[AlbumSetLoader.INDEX_ID] = i;
row[AlbumSetLoader.INDEX_TITLE] = m.getName();
row[AlbumSetLoader.INDEX_COUNT] = m.getMediaItemCount();
+ row[AlbumSetLoader.INDEX_SUPPORTED_OPERATIONS] = m.getSupportedOperations();
MediaItem coverItem = m.getCoverMediaItem();
if (coverItem != null) {
row[AlbumSetLoader.INDEX_TIMESTAMP] = coverItem.getDateInMs();
@@ -147,4 +152,39 @@ public class MediaSetLoader extends AsyncTaskLoader<Cursor> implements LoaderCom
MediaSet ms = mMediaSet.getSubMediaSet(index);
return ms == null ? null : ms.getContentUri();
}
+
+ @Override
+ public ArrayList<Uri> urisForSubItems(Cursor item) {
+ int index = item.getInt(AlbumSetLoader.INDEX_ID);
+ MediaSet ms = mMediaSet.getSubMediaSet(index);
+ if (ms == null) return null;
+ final ArrayList<Uri> result = new ArrayList<Uri>();
+ ms.enumerateMediaItems(new MediaSet.ItemConsumer() {
+ @Override
+ public void consume(int index, MediaItem item) {
+ if (item != null) {
+ result.add(item.getContentUri());
+ }
+ }
+ });
+ return result;
+ }
+
+ @Override
+ public void deleteItemWithPath(Object path) {
+ MediaObject o = mDataManager.getMediaObject((Path) path);
+ if (o != null) {
+ o.delete();
+ }
+ }
+
+ @Override
+ public Object getPathForItem(Cursor item) {
+ int index = item.getInt(AlbumSetLoader.INDEX_ID);
+ MediaSet ms = mMediaSet.getSubMediaSet(index);
+ if (ms != null) {
+ return ms.getPath();
+ }
+ return null;
+ }
}