diff options
Diffstat (limited to 'src/com/android/photos')
-rw-r--r-- | src/com/android/photos/AlbumSetFragment.java | 126 | ||||
-rw-r--r-- | src/com/android/photos/GalleryActivity.java | 145 | ||||
-rw-r--r-- | src/com/android/photos/MultiChoiceManager.java | 190 | ||||
-rw-r--r-- | src/com/android/photos/PhotoSetFragment.java | 139 | ||||
-rw-r--r-- | src/com/android/photos/SelectionManager.java | 76 | ||||
-rw-r--r-- | src/com/android/photos/adapters/AlbumSetCursorAdapter.java | 89 | ||||
-rw-r--r-- | src/com/android/photos/adapters/PhotoThumbnailAdapter.java | 8 | ||||
-rw-r--r-- | src/com/android/photos/data/AlbumSetLoader.java | 7 | ||||
-rw-r--r-- | src/com/android/photos/data/PhotoProvider.java | 27 | ||||
-rw-r--r-- | src/com/android/photos/data/PhotoSetLoader.java | 17 | ||||
-rw-r--r-- | src/com/android/photos/shims/LoaderCompatShim.java | 5 | ||||
-rw-r--r-- | src/com/android/photos/shims/MediaItemsLoader.java | 37 | ||||
-rw-r--r-- | src/com/android/photos/shims/MediaSetLoader.java | 48 | ||||
-rw-r--r-- | src/com/android/photos/views/SquareImageView.java | 53 |
14 files changed, 705 insertions, 262 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 2335658d1..ddf04e365 100644 --- a/src/com/android/photos/GalleryActivity.java +++ b/src/com/android/photos/GalleryActivity.java @@ -21,49 +21,53 @@ import android.app.ActionBar.Tab; import android.app.Activity; import android.app.Fragment; import android.app.FragmentTransaction; +import android.content.Context; import android.content.Intent; import android.os.Bundle; +import android.support.v13.app.FragmentPagerAdapter; +import android.support.v4.view.ViewPager; import android.view.Menu; import android.view.MenuItem; import com.android.camera.CameraActivity; import com.android.gallery3d.R; +import java.util.ArrayList; + public class GalleryActivity extends Activity { - private final String FTAG_PHOTOSET = "PhotoSet"; - private final String FTAG_ALBUMSET = "AlbumSet"; private SelectionManager mSelectionManager; + private ViewPager mViewPager; + private TabsAdapter mTabsAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); + mSelectionManager = new SelectionManager(this); + mViewPager = new ViewPager(this); + mViewPager.setId(R.id.viewpager); + setContentView(mViewPager); - setupActionBar(); - } - - protected SelectionManager getSelectionManager() { - if (mSelectionManager == null) { - mSelectionManager = new SelectionManager(this); - } - return mSelectionManager; - } - - private void setupActionBar() { ActionBar ab = getActionBar(); ab.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); ab.setDisplayShowHomeEnabled(false); ab.setDisplayShowTitleEnabled(false); - Tab tab = ab.newTab(); - tab.setText(R.string.tab_photos); - tab.setTabListener(new TabListener<PhotoSetFragment>(this, - FTAG_PHOTOSET, PhotoSetFragment.class)); - ab.addTab(tab, true); - tab = ab.newTab(); - tab.setText(R.string.tab_albums); - tab.setTabListener(new TabListener<AlbumSetFragment>(this, - FTAG_ALBUMSET, AlbumSetFragment.class)); - ab.addTab(tab); + + mTabsAdapter = new TabsAdapter(this, mViewPager); + mTabsAdapter.addTab(ab.newTab().setText(R.string.tab_photos), + PhotoSetFragment.class, null); + mTabsAdapter.addTab(ab.newTab().setText(R.string.tab_albums), + AlbumSetFragment.class, null); + + if (savedInstanceState != null) { + ab.setSelectedNavigationItem(savedInstanceState.getInt("tab", 0)); + } + } + + @Override + protected void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt("tab", getActionBar().getSelectedNavigationIndex()); } @Override @@ -85,49 +89,88 @@ public class GalleryActivity extends Activity { } } - private static class TabListener<T extends Fragment> implements ActionBar.TabListener { - private Fragment mFragment; - private final Activity mActivity; - private final String mTag; - private final Class<T> mClass; - - /** Constructor used each time a new tab is created. - * @param activity The host Activity, used to instantiate the fragment - * @param tag The identifier tag for the fragment - * @param clz The fragment's Class, used to instantiate the fragment - */ - public TabListener(Activity activity, String tag, Class<T> clz) { + public static class TabsAdapter extends FragmentPagerAdapter implements + ActionBar.TabListener, ViewPager.OnPageChangeListener { + + private final GalleryActivity mActivity; + private final ActionBar mActionBar; + private final ViewPager mViewPager; + private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>(); + + static final class TabInfo { + + private final Class<?> clss; + private final Bundle args; + + TabInfo(Class<?> _class, Bundle _args) { + clss = _class; + args = _args; + } + } + + public TabsAdapter(GalleryActivity activity, ViewPager pager) { + super(activity.getFragmentManager()); mActivity = activity; - mTag = tag; - mClass = clz; + mActionBar = activity.getActionBar(); + mViewPager = pager; + mViewPager.setAdapter(this); + mViewPager.setOnPageChangeListener(this); + } + + public void addTab(ActionBar.Tab tab, Class<?> clss, Bundle args) { + TabInfo info = new TabInfo(clss, args); + tab.setTag(info); + tab.setTabListener(this); + mTabs.add(info); + mActionBar.addTab(tab); + notifyDataSetChanged(); + } + + @Override + public int getCount() { + return mTabs.size(); + } + + @Override + public Fragment getItem(int position) { + TabInfo info = mTabs.get(position); + Fragment item = Fragment.instantiate(mActivity, info.clss.getName(), + info.args); + ((SelectionManager.Client) item).setSelectionManager( + mActivity.mSelectionManager); + return item; } - /* The following are each of the ActionBar.TabListener callbacks */ + @Override + public void onPageScrolled(int position, float positionOffset, + int positionOffsetPixels) { + } + + @Override + public void onPageSelected(int position) { + mActionBar.setSelectedNavigationItem(position); + } + + @Override + public void onPageScrollStateChanged(int state) { + } @Override public void onTabSelected(Tab tab, FragmentTransaction ft) { - // Check if the fragment is already initialized - if (mFragment == null) { - // If not, instantiate and add it to the activity - mFragment = Fragment.instantiate(mActivity, mClass.getName()); - ft.add(android.R.id.content, mFragment, mTag); - } else { - // If it exists, simply attach it in order to show it - ft.attach(mFragment); + Object tag = tab.getTag(); + for (int i = 0; i < mTabs.size(); i++) { + if (mTabs.get(i) == tag) { + mViewPager.setCurrentItem(i); + } } } @Override public void onTabUnselected(Tab tab, FragmentTransaction ft) { - if (mFragment != null) { - // Detach the fragment, because another one is being attached - ft.detach(mFragment); - } } @Override public void onTabReselected(Tab tab, FragmentTransaction ft) { - // User selected the already selected tab. Usually do nothing. } } } 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 d7e61d19a..ce340c731 100644 --- a/src/com/android/photos/SelectionManager.java +++ b/src/com/android/photos/SelectionManager.java @@ -16,22 +16,22 @@ package com.android.photos; -import android.annotation.TargetApi; import android.app.Activity; import android.content.Intent; import android.net.Uri; import android.nfc.NfcAdapter; +import android.nfc.NfcAdapter.CreateBeamUrisCallback; import android.nfc.NfcEvent; 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; -public class SelectionManager implements NfcAdapter.CreateBeamUrisCallback { +public class SelectionManager { private Activity mActivity; private NfcAdapter mNfcAdapter; private SelectedUriSource mUriSource; @@ -41,12 +41,23 @@ public class SelectionManager implements NfcAdapter.CreateBeamUrisCallback { public ArrayList<Uri> getSelectedShareableUris(); } - @TargetApi(16) + public interface Client { + public void setSelectionManager(SelectionManager manager); + } + public SelectionManager(Activity activity) { mActivity = activity; if (ApiHelper.AT_LEAST_16) { mNfcAdapter = NfcAdapter.getDefaultAdapter(mActivity); - mNfcAdapter.setBeamPushUrisCallback(this, mActivity); + mNfcAdapter.setBeamPushUrisCallback(new CreateBeamUrisCallback() { + @Override + public Uri[] createBeamUris(NfcEvent arg0) { + // This will have been preceded by a call to onItemSelectedStateChange + if (mCachedShareableUris == null) return null; + return mCachedShareableUris.toArray( + new Uri[mCachedShareableUris.size()]); + } + }, mActivity); } } @@ -69,10 +80,10 @@ public class SelectionManager implements NfcAdapter.CreateBeamUrisCallback { 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; @@ -86,24 +97,42 @@ public class SelectionManager implements NfcAdapter.CreateBeamUrisCallback { 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() { @@ -116,11 +145,4 @@ public class SelectionManager implements NfcAdapter.CreateBeamUrisCallback { mShareIntent.removeExtra(Intent.EXTRA_STREAM); mShareIntent.setAction(null).setType(null); } - - @Override - public Uri[] createBeamUris(NfcEvent event) { - // This will have been preceded by a call to onItemSelectedStateChange - if (mCachedShareableUris == null) return null; - return mCachedShareableUris.toArray(new Uri[mCachedShareableUris.size()]); - } } 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/adapters/PhotoThumbnailAdapter.java b/src/com/android/photos/adapters/PhotoThumbnailAdapter.java index 5715795da..1190b8c85 100644 --- a/src/com/android/photos/adapters/PhotoThumbnailAdapter.java +++ b/src/com/android/photos/adapters/PhotoThumbnailAdapter.java @@ -22,9 +22,7 @@ import android.graphics.drawable.Drawable; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.ViewGroup.LayoutParams; import android.widget.CursorAdapter; -import android.widget.GridView; import android.widget.ImageView; import com.android.gallery3d.R; @@ -48,7 +46,7 @@ public class PhotoThumbnailAdapter extends CursorAdapter implements GalleryThumb @Override public void bindView(View view, Context context, Cursor cursor) { - ImageView iv = (ImageView) view; + ImageView iv = (ImageView) view.findViewById(R.id.thumbnail); Drawable recycle = iv.getDrawable(); Drawable drawable = mDrawableFactory.drawableForItem(cursor, recycle); if (recycle != drawable) { @@ -59,10 +57,6 @@ public class PhotoThumbnailAdapter extends CursorAdapter implements GalleryThumb @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { View view = mInflater.inflate(R.layout.photo_set_item, parent, false); - LayoutParams params = view.getLayoutParams(); - int columnWidth = ((GridView) parent).getColumnWidth(); - params.height = columnWidth; - view.setLayoutParams(params); return view; } 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/PhotoProvider.java b/src/com/android/photos/data/PhotoProvider.java index 7127f979f..8413206b1 100644 --- a/src/com/android/photos/data/PhotoProvider.java +++ b/src/com/android/photos/data/PhotoProvider.java @@ -84,7 +84,7 @@ public class PhotoProvider extends SQLiteContentProvider { */ public static interface Photos extends BaseColumns { /** Internal database table used for basic photo information. */ - public static final String TABLE = "photo"; + public static final String TABLE = "photos"; /** Content URI for basic photo and video information. */ public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE); @@ -123,7 +123,7 @@ public class PhotoProvider extends SQLiteContentProvider { */ public static interface Albums extends BaseColumns { /** Internal database table used album information. */ - public static final String TABLE = "album"; + public static final String TABLE = "albums"; /** Content URI for album information. */ public static final Uri CONTENT_URI = Uri.withAppendedPath(BASE_CONTENT_URI, TABLE); @@ -267,7 +267,7 @@ public class PhotoProvider extends SQLiteContentProvider { Photos.MIME_TYPE, }; - private static final String[] BASE_COLUMNS_ID = { + protected static final String[] BASE_COLUMNS_ID = { BaseColumns._ID, }; @@ -502,15 +502,17 @@ public class PhotoProvider extends SQLiteContentProvider { String[] selectionArgs, Uri uri) { switch (match) { case MATCH_PHOTO: - case MATCH_PHOTO_ID: { + case MATCH_PHOTO_ID: deleteCascadeMetadata(db, selection, selectionArgs); break; - } case MATCH_ALBUM: - case MATCH_ALBUM_ID: { + case MATCH_ALBUM_ID: deleteCascadePhotos(db, selection, selectionArgs); break; - } + case MATCH_ACCOUNT: + case MATCH_ACCOUNT_ID: + deleteCascadeAccounts(db, selection, selectionArgs); + break; } String table = getTableFromMatch(match, uri); int deleted = db.delete(table, selection, selectionArgs); @@ -520,6 +522,17 @@ public class PhotoProvider extends SQLiteContentProvider { return deleted; } + private void deleteCascadeAccounts(SQLiteDatabase db, String accountSelect, String[] args) { + // Delete all photos associated with the account + String photoWhere = nestWhere(Photos.ACCOUNT_ID, Accounts.TABLE, accountSelect); + deleteCascadeMetadata(db, photoWhere, args); + db.delete(Photos.TABLE, photoWhere, args); + + // Delete all albums that are associated with this account + String albumWhere = nestWhere(Albums.ACCOUNT_ID, Accounts.TABLE, accountSelect); + db.delete(Albums.TABLE, albumWhere, args); + } + private void deleteCascadePhotos(SQLiteDatabase db, String albumSelect, String[] selectArgs) { String photoWhere = nestWhere(Photos.ALBUM_ID, Albums.TABLE, albumSelect); 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; + } } diff --git a/src/com/android/photos/views/SquareImageView.java b/src/com/android/photos/views/SquareImageView.java new file mode 100644 index 000000000..14eff1077 --- /dev/null +++ b/src/com/android/photos/views/SquareImageView.java @@ -0,0 +1,53 @@ +/* + * 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.views; + +import android.content.Context; +import android.util.AttributeSet; +import android.widget.ImageView; + + +public class SquareImageView extends ImageView { + + public SquareImageView(Context context) { + super(context); + } + + public SquareImageView(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public SquareImageView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + int widthMode = MeasureSpec.getMode(widthMeasureSpec); + int heightMode = MeasureSpec.getMode(heightMeasureSpec); + if (widthMode == MeasureSpec.EXACTLY && heightMode != MeasureSpec.EXACTLY) { + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = width; + if (heightMode == MeasureSpec.AT_MOST) { + height = Math.min(height, MeasureSpec.getSize(heightMeasureSpec)); + } + setMeasuredDimension(width, height); + } else { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + } + } +} |