| /* |
| * Copyright (C) 2010 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.gallery3d.app; |
| |
| import com.android.gallery3d.R; |
| import com.android.gallery3d.common.Utils; |
| import com.android.gallery3d.data.DataManager; |
| import com.android.gallery3d.data.MediaDetails; |
| import com.android.gallery3d.data.MediaObject; |
| import com.android.gallery3d.data.MediaSet; |
| import com.android.gallery3d.data.Path; |
| import com.android.gallery3d.picasasource.PicasaSource; |
| import com.android.gallery3d.settings.GallerySettings; |
| import com.android.gallery3d.ui.ActionModeHandler; |
| import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener; |
| import com.android.gallery3d.ui.AlbumSetView; |
| import com.android.gallery3d.ui.DetailsWindow; |
| import com.android.gallery3d.ui.DetailsWindow.CloseListener; |
| import com.android.gallery3d.ui.GLCanvas; |
| import com.android.gallery3d.ui.GLView; |
| import com.android.gallery3d.ui.GridDrawer; |
| import com.android.gallery3d.ui.HighlightDrawer; |
| import com.android.gallery3d.ui.PositionProvider; |
| import com.android.gallery3d.ui.PositionRepository; |
| import com.android.gallery3d.ui.PositionRepository.Position; |
| import com.android.gallery3d.ui.SelectionManager; |
| import com.android.gallery3d.ui.SlotView; |
| import com.android.gallery3d.ui.StaticBackground; |
| import com.android.gallery3d.ui.SynchronizedHandler; |
| import com.android.gallery3d.util.GalleryUtils; |
| |
| import android.app.Activity; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.graphics.Rect; |
| import android.os.Bundle; |
| import android.os.Message; |
| import android.provider.MediaStore; |
| import android.view.ActionMode; |
| import android.view.Menu; |
| import android.view.MenuInflater; |
| import android.view.MenuItem; |
| import android.view.View.MeasureSpec; |
| import android.widget.Toast; |
| |
| public class AlbumSetPage extends ActivityState implements |
| SelectionManager.SelectionListener, GalleryActionBar.ClusterRunner, |
| EyePosition.EyePositionListener { |
| @SuppressWarnings("unused") |
| private static final String TAG = "AlbumSetPage"; |
| |
| public static final String KEY_MEDIA_PATH = "media-path"; |
| public static final String KEY_SET_TITLE = "set-title"; |
| public static final String KEY_SET_SUBTITLE = "set-subtitle"; |
| private static final int DATA_CACHE_SIZE = 256; |
| private static final int REQUEST_DO_ANIMATION = 1; |
| private static final int MSG_GOTO_MANAGE_CACHE_PAGE = 1; |
| |
| private boolean mIsActive = false; |
| private StaticBackground mStaticBackground; |
| private AlbumSetView mAlbumSetView; |
| |
| private MediaSet mMediaSet; |
| private String mTitle; |
| private String mSubtitle; |
| private boolean mShowClusterTabs; |
| |
| protected SelectionManager mSelectionManager; |
| private AlbumSetDataAdapter mAlbumSetDataAdapter; |
| private GridDrawer mGridDrawer; |
| private HighlightDrawer mHighlightDrawer; |
| |
| private boolean mGetContent; |
| private boolean mGetAlbum; |
| private ActionMode mActionMode; |
| private ActionModeHandler mActionModeHandler; |
| private DetailsWindow mDetailsWindow; |
| private boolean mShowDetails; |
| private EyePosition mEyePosition; |
| |
| // The eyes' position of the user, the origin is at the center of the |
| // device and the unit is in pixels. |
| private float mX; |
| private float mY; |
| private float mZ; |
| |
| private SynchronizedHandler mHandler; |
| |
| private GLView mRootPane = new GLView() { |
| private float mMatrix[] = new float[16]; |
| |
| @Override |
| protected void onLayout( |
| boolean changed, int left, int top, int right, int bottom) { |
| mStaticBackground.layout(0, 0, right - left, bottom - top); |
| mEyePosition.resetPosition(); |
| |
| int slotViewTop = GalleryActionBar.getHeight((Activity) mActivity); |
| int slotViewBottom = bottom - top; |
| int slotViewRight = right - left; |
| |
| if (mShowDetails) { |
| mDetailsWindow.measure( |
| MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); |
| int width = mDetailsWindow.getMeasuredWidth(); |
| int detailLeft = right - left - width; |
| slotViewRight = detailLeft; |
| mDetailsWindow.layout(detailLeft, slotViewTop, detailLeft + width, |
| bottom - top); |
| } else { |
| mAlbumSetView.setSelectionDrawer(mGridDrawer); |
| } |
| |
| mAlbumSetView.layout(0, slotViewTop, slotViewRight, slotViewBottom); |
| PositionRepository.getInstance(mActivity).setOffset( |
| 0, slotViewTop); |
| } |
| |
| @Override |
| protected void render(GLCanvas canvas) { |
| canvas.save(GLCanvas.SAVE_FLAG_MATRIX); |
| GalleryUtils.setViewPointMatrix(mMatrix, |
| getWidth() / 2 + mX, getHeight() / 2 + mY, mZ); |
| canvas.multiplyMatrix(mMatrix, 0); |
| super.render(canvas); |
| canvas.restore(); |
| } |
| }; |
| |
| @Override |
| public void onEyePositionChanged(float x, float y, float z) { |
| mRootPane.lockRendering(); |
| mX = x; |
| mY = y; |
| mZ = z; |
| mRootPane.unlockRendering(); |
| mRootPane.invalidate(); |
| } |
| |
| @Override |
| public void onBackPressed() { |
| if (mShowDetails) { |
| hideDetails(); |
| } else if (mSelectionManager.inSelectionMode()) { |
| mSelectionManager.leaveSelectionMode(); |
| } else { |
| mAlbumSetView.savePositions( |
| PositionRepository.getInstance(mActivity)); |
| super.onBackPressed(); |
| } |
| } |
| |
| private void savePositions(int slotIndex, int center[]) { |
| Rect offset = new Rect(); |
| mRootPane.getBoundsOf(mAlbumSetView, offset); |
| mAlbumSetView.savePositions(PositionRepository.getInstance(mActivity)); |
| Rect r = mAlbumSetView.getSlotRect(slotIndex); |
| int scrollX = mAlbumSetView.getScrollX(); |
| int scrollY = mAlbumSetView.getScrollY(); |
| center[0] = offset.left + (r.left + r.right) / 2 - scrollX; |
| center[1] = offset.top + (r.top + r.bottom) / 2 - scrollY; |
| } |
| |
| public void onSingleTapUp(int slotIndex) { |
| MediaSet targetSet = mAlbumSetDataAdapter.getMediaSet(slotIndex); |
| if (targetSet == null) return; // Content is dirty, we shall reload soon |
| |
| if (mShowDetails) { |
| Path path = targetSet.getPath(); |
| mHighlightDrawer.setHighlightItem(path); |
| mDetailsWindow.reloadDetails(slotIndex); |
| } else if (!mSelectionManager.inSelectionMode()) { |
| Bundle data = new Bundle(getData()); |
| String mediaPath = targetSet.getPath().toString(); |
| int[] center = new int[2]; |
| savePositions(slotIndex, center); |
| data.putIntArray(AlbumPage.KEY_SET_CENTER, center); |
| if (mGetAlbum && targetSet.isLeafAlbum()) { |
| Activity activity = (Activity) mActivity; |
| Intent result = new Intent() |
| .putExtra(AlbumPicker.KEY_ALBUM_PATH, targetSet.getPath().toString()); |
| activity.setResult(Activity.RESULT_OK, result); |
| activity.finish(); |
| } else if (targetSet.getSubMediaSetCount() > 0) { |
| data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath); |
| mActivity.getStateManager().startStateForResult( |
| AlbumSetPage.class, REQUEST_DO_ANIMATION, data); |
| } else { |
| if (!mGetContent && (targetSet.getSupportedOperations() |
| & MediaObject.SUPPORT_IMPORT) != 0) { |
| data.putBoolean(AlbumPage.KEY_AUTO_SELECT_ALL, true); |
| } |
| data.putString(AlbumPage.KEY_MEDIA_PATH, mediaPath); |
| boolean inAlbum = mActivity.getStateManager().hasStateClass(AlbumPage.class); |
| // We only show cluster menu in the first AlbumPage in stack |
| data.putBoolean(AlbumPage.KEY_SHOW_CLUSTER_MENU, !inAlbum); |
| mActivity.getStateManager().startStateForResult( |
| AlbumPage.class, REQUEST_DO_ANIMATION, data); |
| } |
| } else { |
| mSelectionManager.toggle(targetSet.getPath()); |
| mAlbumSetView.invalidate(); |
| } |
| } |
| |
| public void onLongTap(int slotIndex) { |
| if (mGetContent || mGetAlbum) return; |
| if (mShowDetails) { |
| onSingleTapUp(slotIndex); |
| } else { |
| MediaSet set = mAlbumSetDataAdapter.getMediaSet(slotIndex); |
| if (set == null) return; |
| mSelectionManager.setAutoLeaveSelectionMode(true); |
| mSelectionManager.toggle(set.getPath()); |
| mAlbumSetView.invalidate(); |
| } |
| } |
| |
| public void doCluster(int clusterType) { |
| String basePath = mMediaSet.getPath().toString(); |
| String newPath = FilterUtils.switchClusterPath(basePath, clusterType); |
| Bundle data = new Bundle(getData()); |
| data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath); |
| mAlbumSetView.savePositions(PositionRepository.getInstance(mActivity)); |
| mActivity.getStateManager().switchState(this, AlbumSetPage.class, data); |
| } |
| |
| public void doFilter(int filterType) { |
| String basePath = mMediaSet.getPath().toString(); |
| String newPath = FilterUtils.switchFilterPath(basePath, filterType); |
| Bundle data = new Bundle(getData()); |
| data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath); |
| mAlbumSetView.savePositions(PositionRepository.getInstance(mActivity)); |
| mActivity.getStateManager().switchState(this, AlbumSetPage.class, data); |
| } |
| |
| public void onOperationComplete() { |
| mAlbumSetView.invalidate(); |
| // TODO: enable animation |
| } |
| |
| @Override |
| public void onCreate(Bundle data, Bundle restoreState) { |
| mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { |
| @Override |
| public void handleMessage(Message message) { |
| Utils.assertTrue(message.what == MSG_GOTO_MANAGE_CACHE_PAGE); |
| Bundle data = new Bundle(); |
| String mediaPath = mActivity.getDataManager().getTopSetPath( |
| DataManager.INCLUDE_ALL); |
| data.putString(AlbumSetPage.KEY_MEDIA_PATH, mediaPath); |
| mActivity.getStateManager().startState(ManageCachePage.class, data); |
| } |
| }; |
| |
| initializeViews(); |
| initializeData(data); |
| mGetContent = data.getBoolean(Gallery.KEY_GET_CONTENT, false); |
| mGetAlbum = data.getBoolean(Gallery.KEY_GET_ALBUM, false); |
| mTitle = data.getString(AlbumSetPage.KEY_SET_TITLE); |
| mSubtitle = data.getString(AlbumSetPage.KEY_SET_SUBTITLE); |
| mEyePosition = new EyePosition(mActivity.getAndroidContext(), this); |
| |
| startTransition(); |
| } |
| |
| @Override |
| public void onPause() { |
| super.onPause(); |
| mIsActive = false; |
| mActionModeHandler.pause(); |
| mAlbumSetDataAdapter.pause(); |
| mAlbumSetView.pause(); |
| mEyePosition.pause(); |
| if (mDetailsWindow != null) { |
| mDetailsWindow.pause(); |
| } |
| GalleryActionBar actionBar = mActivity.getGalleryActionBar(); |
| if (actionBar != null) actionBar.hideClusterTabs(); |
| } |
| |
| @Override |
| public void onResume() { |
| super.onResume(); |
| mIsActive = true; |
| setContentPane(mRootPane); |
| mAlbumSetDataAdapter.resume(); |
| mAlbumSetView.resume(); |
| mEyePosition.resume(); |
| mActionModeHandler.resume(); |
| GalleryActionBar actionBar = mActivity.getGalleryActionBar(); |
| if (mShowClusterTabs && actionBar != null) actionBar.showClusterTabs(this); |
| } |
| |
| private void initializeData(Bundle data) { |
| String mediaPath = data.getString(AlbumSetPage.KEY_MEDIA_PATH); |
| mMediaSet = mActivity.getDataManager().getMediaSet(mediaPath); |
| mSelectionManager.setSourceMediaSet(mMediaSet); |
| mAlbumSetDataAdapter = new AlbumSetDataAdapter( |
| mActivity, mMediaSet, DATA_CACHE_SIZE); |
| mAlbumSetDataAdapter.setLoadingListener(new MyLoadingListener()); |
| mAlbumSetView.setModel(mAlbumSetDataAdapter); |
| } |
| |
| private void initializeViews() { |
| mSelectionManager = new SelectionManager(mActivity, true); |
| mSelectionManager.setSelectionListener(this); |
| mStaticBackground = new StaticBackground(mActivity.getAndroidContext()); |
| mRootPane.addComponent(mStaticBackground); |
| |
| mGridDrawer = new GridDrawer((Context) mActivity, mSelectionManager); |
| Config.AlbumSetPage config = Config.AlbumSetPage.get((Context) mActivity); |
| mAlbumSetView = new AlbumSetView(mActivity, mGridDrawer, |
| config.slotWidth, config.slotHeight, |
| config.displayItemSize, config.labelFontSize, |
| config.labelOffsetY, config.labelMargin); |
| mAlbumSetView.setListener(new SlotView.SimpleListener() { |
| @Override |
| public void onSingleTapUp(int slotIndex) { |
| AlbumSetPage.this.onSingleTapUp(slotIndex); |
| } |
| @Override |
| public void onLongTap(int slotIndex) { |
| AlbumSetPage.this.onLongTap(slotIndex); |
| } |
| }); |
| |
| mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager); |
| mActionModeHandler.setActionModeListener(new ActionModeListener() { |
| public boolean onActionItemClicked(MenuItem item) { |
| return onItemSelected(item); |
| } |
| }); |
| mRootPane.addComponent(mAlbumSetView); |
| |
| mStaticBackground.setImage(R.drawable.background, |
| R.drawable.background_portrait); |
| } |
| |
| @Override |
| protected boolean onCreateActionBar(Menu menu) { |
| Activity activity = (Activity) mActivity; |
| GalleryActionBar actionBar = mActivity.getGalleryActionBar(); |
| MenuInflater inflater = activity.getMenuInflater(); |
| |
| final boolean inAlbum = mActivity.getStateManager().hasStateClass( |
| AlbumPage.class); |
| |
| if (mGetContent) { |
| inflater.inflate(R.menu.pickup, menu); |
| int typeBits = mData.getInt( |
| Gallery.KEY_TYPE_BITS, DataManager.INCLUDE_IMAGE); |
| int id = R.string.select_image; |
| if ((typeBits & DataManager.INCLUDE_VIDEO) != 0) { |
| id = (typeBits & DataManager.INCLUDE_IMAGE) == 0 |
| ? R.string.select_video |
| : R.string.select_item; |
| } |
| actionBar.setTitle(id); |
| } else if (mGetAlbum) { |
| inflater.inflate(R.menu.pickup, menu); |
| actionBar.setTitle(R.string.select_album); |
| } else { |
| mShowClusterTabs = !inAlbum; |
| inflater.inflate(R.menu.albumset, menu); |
| if (mTitle != null) { |
| actionBar.setTitle(mTitle); |
| } else { |
| actionBar.setTitle(activity.getApplicationInfo().labelRes); |
| } |
| MenuItem selectItem = menu.findItem(R.id.action_select); |
| |
| if (selectItem != null) { |
| boolean selectAlbums = !inAlbum && |
| actionBar.getClusterTypeAction() == FilterUtils.CLUSTER_BY_ALBUM; |
| if (selectAlbums) { |
| selectItem.setTitle(R.string.select_album); |
| } else { |
| selectItem.setTitle(R.string.select_group); |
| } |
| } |
| |
| MenuItem switchCamera = menu.findItem(R.id.action_camera); |
| if (switchCamera != null) { |
| switchCamera.setVisible(GalleryUtils.isCameraAvailable(activity)); |
| } |
| |
| actionBar.setSubtitle(mSubtitle); |
| } |
| return true; |
| } |
| |
| @Override |
| protected boolean onItemSelected(MenuItem item) { |
| Activity activity = (Activity) mActivity; |
| switch (item.getItemId()) { |
| case R.id.action_select: |
| mSelectionManager.setAutoLeaveSelectionMode(false); |
| mSelectionManager.enterSelectionMode(); |
| return true; |
| case R.id.action_details: |
| if (mAlbumSetDataAdapter.size() != 0) { |
| if (mShowDetails) { |
| hideDetails(); |
| } else { |
| showDetails(); |
| } |
| } else { |
| Toast.makeText(activity, |
| activity.getText(R.string.no_albums_alert), |
| Toast.LENGTH_SHORT).show(); |
| } |
| return true; |
| case R.id.action_camera: { |
| Intent intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA) |
| .setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
| | Intent.FLAG_ACTIVITY_NEW_TASK); |
| activity.startActivity(intent); |
| return true; |
| } |
| case R.id.action_manage_offline: { |
| mHandler.sendEmptyMessage(MSG_GOTO_MANAGE_CACHE_PAGE); |
| return true; |
| } |
| case R.id.action_sync_picasa_albums: { |
| PicasaSource.requestSync(activity); |
| return true; |
| } |
| case R.id.action_settings: { |
| activity.startActivity(new Intent(activity, GallerySettings.class)); |
| return true; |
| } |
| default: |
| return false; |
| } |
| } |
| |
| @Override |
| protected void onStateResult(int requestCode, int resultCode, Intent data) { |
| switch (requestCode) { |
| case REQUEST_DO_ANIMATION: { |
| startTransition(); |
| } |
| } |
| } |
| |
| private void startTransition() { |
| final PositionRepository repository = |
| PositionRepository.getInstance(mActivity); |
| mAlbumSetView.startTransition(new PositionProvider() { |
| private Position mTempPosition = new Position(); |
| public Position getPosition(long identity, Position target) { |
| Position p = repository.get(identity); |
| if (p == null) { |
| p = mTempPosition; |
| p.set(target.x, target.y, 128, target.theta, 1); |
| } |
| return p; |
| } |
| }); |
| } |
| |
| private String getSelectedString() { |
| GalleryActionBar actionBar = mActivity.getGalleryActionBar(); |
| int count = mSelectionManager.getSelectedCount(); |
| int action = actionBar.getClusterTypeAction(); |
| int string = action == FilterUtils.CLUSTER_BY_ALBUM |
| ? R.plurals.number_of_albums_selected |
| : R.plurals.number_of_groups_selected; |
| String format = mActivity.getResources().getQuantityString(string, count); |
| return String.format(format, count); |
| } |
| |
| public void onSelectionModeChange(int mode) { |
| |
| switch (mode) { |
| case SelectionManager.ENTER_SELECTION_MODE: { |
| mActivity.getGalleryActionBar().hideClusterTabs(); |
| mActionMode = mActionModeHandler.startActionMode(); |
| break; |
| } |
| case SelectionManager.LEAVE_SELECTION_MODE: { |
| mActionMode.finish(); |
| mActivity.getGalleryActionBar().showClusterTabs(this); |
| mRootPane.invalidate(); |
| break; |
| } |
| case SelectionManager.SELECT_ALL_MODE: { |
| mActionModeHandler.setTitle(getSelectedString()); |
| mRootPane.invalidate(); |
| break; |
| } |
| } |
| } |
| |
| public void onSelectionChange(Path path, boolean selected) { |
| Utils.assertTrue(mActionMode != null); |
| mActionModeHandler.setTitle(getSelectedString()); |
| mActionModeHandler.updateSupportedOperation(path, selected); |
| } |
| |
| private void hideDetails() { |
| mShowDetails = false; |
| mAlbumSetView.setSelectionDrawer(mGridDrawer); |
| mDetailsWindow.hide(); |
| } |
| |
| private void showDetails() { |
| mShowDetails = true; |
| if (mDetailsWindow == null) { |
| mHighlightDrawer = new HighlightDrawer(mActivity.getAndroidContext()); |
| mDetailsWindow = new DetailsWindow(mActivity, new MyDetailsSource()); |
| mDetailsWindow.setCloseListener(new CloseListener() { |
| public void onClose() { |
| hideDetails(); |
| } |
| }); |
| mRootPane.addComponent(mDetailsWindow); |
| } |
| mAlbumSetView.setSelectionDrawer(mHighlightDrawer); |
| mDetailsWindow.show(); |
| } |
| |
| private class MyLoadingListener implements LoadingListener { |
| public void onLoadingStarted() { |
| GalleryUtils.setSpinnerVisibility((Activity) mActivity, true); |
| } |
| |
| public void onLoadingFinished() { |
| if (!mIsActive) return; |
| GalleryUtils.setSpinnerVisibility((Activity) mActivity, false); |
| if (mAlbumSetDataAdapter.size() == 0) { |
| Toast.makeText((Context) mActivity, |
| R.string.empty_album, Toast.LENGTH_LONG).show(); |
| if (mActivity.getStateManager().getStateCount() > 1) { |
| mActivity.getStateManager().finishState(AlbumSetPage.this); |
| } |
| } |
| } |
| } |
| |
| private class MyDetailsSource implements DetailsWindow.DetailsSource { |
| private int mIndex; |
| public int size() { |
| return mAlbumSetDataAdapter.size(); |
| } |
| |
| // If requested index is out of active window, suggest a valid index. |
| // If there is no valid index available, return -1. |
| public int findIndex(int indexHint) { |
| if (mAlbumSetDataAdapter.isActive(indexHint)) { |
| mIndex = indexHint; |
| } else { |
| mIndex = mAlbumSetDataAdapter.getActiveStart(); |
| if (!mAlbumSetDataAdapter.isActive(mIndex)) { |
| return -1; |
| } |
| } |
| return mIndex; |
| } |
| |
| public MediaDetails getDetails() { |
| MediaObject item = mAlbumSetDataAdapter.getMediaSet(mIndex); |
| if (item != null) { |
| mHighlightDrawer.setHighlightItem(item.getPath()); |
| return item.getDetails(); |
| } else { |
| return null; |
| } |
| } |
| } |
| } |