diff options
author | Sascha Haeberling <haeberling@google.com> | 2013-08-06 11:43:02 -0700 |
---|---|---|
committer | Sascha Haeberling <haeberling@google.com> | 2013-08-06 11:43:02 -0700 |
commit | 8e963a5a6016d246184ed65906f9d103e92b17e2 (patch) | |
tree | 02eb244ea4a20d9aa8e43916a40b876be8935d11 /src/com/android/gallery3d/ui | |
parent | 4fc90b07dcf316c7ce6c5313af8202e84bc85603 (diff) | |
download | android_packages_apps_Snap-8e963a5a6016d246184ed65906f9d103e92b17e2.tar.gz android_packages_apps_Snap-8e963a5a6016d246184ed65906f9d103e92b17e2.tar.bz2 android_packages_apps_Snap-8e963a5a6016d246184ed65906f9d103e92b17e2.zip |
This removes all non-Camera stuff from Camera2.
Note: Camera2 is a clone of Gallery2 right now.
Note 2: I will bring .mk files back later.
Change-Id: Ida958654296f5ebaacb6bb0ff59d52a7c37ce6fc
Diffstat (limited to 'src/com/android/gallery3d/ui')
52 files changed, 0 insertions, 13598 deletions
diff --git a/src/com/android/gallery3d/ui/AbstractSlotRenderer.java b/src/com/android/gallery3d/ui/AbstractSlotRenderer.java deleted file mode 100644 index 729439dc3..000000000 --- a/src/com/android/gallery3d/ui/AbstractSlotRenderer.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.content.Context; -import android.graphics.Rect; - -import com.android.gallery3d.R; -import com.android.gallery3d.glrenderer.FadeOutTexture; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.NinePatchTexture; -import com.android.gallery3d.glrenderer.ResourceTexture; -import com.android.gallery3d.glrenderer.Texture; - -public abstract class AbstractSlotRenderer implements SlotView.SlotRenderer { - - private final ResourceTexture mVideoOverlay; - private final ResourceTexture mVideoPlayIcon; - private final ResourceTexture mPanoramaIcon; - private final NinePatchTexture mFramePressed; - private final NinePatchTexture mFrameSelected; - private FadeOutTexture mFramePressedUp; - - protected AbstractSlotRenderer(Context context) { - mVideoOverlay = new ResourceTexture(context, R.drawable.ic_video_thumb); - mVideoPlayIcon = new ResourceTexture(context, R.drawable.ic_gallery_play); - mPanoramaIcon = new ResourceTexture(context, R.drawable.ic_360pano_holo_light); - mFramePressed = new NinePatchTexture(context, R.drawable.grid_pressed); - mFrameSelected = new NinePatchTexture(context, R.drawable.grid_selected); - } - - protected void drawContent(GLCanvas canvas, - Texture content, int width, int height, int rotation) { - canvas.save(GLCanvas.SAVE_FLAG_MATRIX); - - // The content is always rendered in to the largest square that fits - // inside the slot, aligned to the top of the slot. - width = height = Math.min(width, height); - if (rotation != 0) { - canvas.translate(width / 2, height / 2); - canvas.rotate(rotation, 0, 0, 1); - canvas.translate(-width / 2, -height / 2); - } - - // Fit the content into the box - float scale = Math.min( - (float) width / content.getWidth(), - (float) height / content.getHeight()); - canvas.scale(scale, scale, 1); - content.draw(canvas, 0, 0); - - canvas.restore(); - } - - protected void drawVideoOverlay(GLCanvas canvas, int width, int height) { - // Scale the video overlay to the height of the thumbnail and put it - // on the left side. - ResourceTexture v = mVideoOverlay; - float scale = (float) height / v.getHeight(); - int w = Math.round(scale * v.getWidth()); - int h = Math.round(scale * v.getHeight()); - v.draw(canvas, 0, 0, w, h); - - int s = Math.min(width, height) / 6; - mVideoPlayIcon.draw(canvas, (width - s) / 2, (height - s) / 2, s, s); - } - - protected void drawPanoramaIcon(GLCanvas canvas, int width, int height) { - int iconSize = Math.min(width, height) / 6; - mPanoramaIcon.draw(canvas, (width - iconSize) / 2, (height - iconSize) / 2, - iconSize, iconSize); - } - - protected boolean isPressedUpFrameFinished() { - if (mFramePressedUp != null) { - if (mFramePressedUp.isAnimating()) { - return false; - } else { - mFramePressedUp = null; - } - } - return true; - } - - protected void drawPressedUpFrame(GLCanvas canvas, int width, int height) { - if (mFramePressedUp == null) { - mFramePressedUp = new FadeOutTexture(mFramePressed); - } - drawFrame(canvas, mFramePressed.getPaddings(), mFramePressedUp, 0, 0, width, height); - } - - protected void drawPressedFrame(GLCanvas canvas, int width, int height) { - drawFrame(canvas, mFramePressed.getPaddings(), mFramePressed, 0, 0, width, height); - } - - protected void drawSelectedFrame(GLCanvas canvas, int width, int height) { - drawFrame(canvas, mFrameSelected.getPaddings(), mFrameSelected, 0, 0, width, height); - } - - protected static void drawFrame(GLCanvas canvas, Rect padding, Texture frame, - int x, int y, int width, int height) { - frame.draw(canvas, x - padding.left, y - padding.top, width + padding.left + padding.right, - height + padding.top + padding.bottom); - } -} diff --git a/src/com/android/gallery3d/ui/ActionModeHandler.java b/src/com/android/gallery3d/ui/ActionModeHandler.java deleted file mode 100644 index 6b4f10312..000000000 --- a/src/com/android/gallery3d/ui/ActionModeHandler.java +++ /dev/null @@ -1,501 +0,0 @@ -/* - * 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.ui; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Intent; -import android.net.Uri; -import android.nfc.NfcAdapter; -import android.os.Handler; -import android.view.ActionMode; -import android.view.ActionMode.Callback; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.Button; -import android.widget.ShareActionProvider; -import android.widget.ShareActionProvider.OnShareTargetSelectedListener; - -import com.android.gallery3d.R; -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.ui.MenuExecutor.ProgressListener; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.ThreadPool.Job; -import com.android.gallery3d.util.ThreadPool.JobContext; - -import java.util.ArrayList; - -public class ActionModeHandler implements Callback, PopupList.OnPopupItemClickListener { - - @SuppressWarnings("unused") - private static final String TAG = "ActionModeHandler"; - - private static final int MAX_SELECTED_ITEMS_FOR_SHARE_INTENT = 300; - private static final int MAX_SELECTED_ITEMS_FOR_PANORAMA_SHARE_INTENT = 10; - - private static final int SUPPORT_MULTIPLE_MASK = MediaObject.SUPPORT_DELETE - | MediaObject.SUPPORT_ROTATE | MediaObject.SUPPORT_SHARE - | MediaObject.SUPPORT_CACHE; - - public interface ActionModeListener { - public boolean onActionItemClicked(MenuItem item); - } - - private final AbstractGalleryActivity mActivity; - private final MenuExecutor mMenuExecutor; - private final SelectionManager mSelectionManager; - private final NfcAdapter mNfcAdapter; - private Menu mMenu; - private MenuItem mSharePanoramaMenuItem; - private MenuItem mShareMenuItem; - private ShareActionProvider mSharePanoramaActionProvider; - private ShareActionProvider mShareActionProvider; - private SelectionMenu mSelectionMenu; - private ActionModeListener mListener; - private Future<?> mMenuTask; - private final Handler mMainHandler; - private ActionMode mActionMode; - - private static class GetAllPanoramaSupports implements PanoramaSupportCallback { - private int mNumInfoRequired; - private JobContext mJobContext; - public boolean mAllPanoramas = true; - public boolean mAllPanorama360 = true; - public boolean mHasPanorama360 = false; - private Object mLock = new Object(); - - public GetAllPanoramaSupports(ArrayList<MediaObject> mediaObjects, JobContext jc) { - mJobContext = jc; - mNumInfoRequired = mediaObjects.size(); - for (MediaObject mediaObject : mediaObjects) { - mediaObject.getPanoramaSupport(this); - } - } - - @Override - public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama, - boolean isPanorama360) { - synchronized (mLock) { - mNumInfoRequired--; - mAllPanoramas = isPanorama && mAllPanoramas; - mAllPanorama360 = isPanorama360 && mAllPanorama360; - mHasPanorama360 = mHasPanorama360 || isPanorama360; - if (mNumInfoRequired == 0 || mJobContext.isCancelled()) { - mLock.notifyAll(); - } - } - } - - public void waitForPanoramaSupport() { - synchronized (mLock) { - while (mNumInfoRequired != 0 && !mJobContext.isCancelled()) { - try { - mLock.wait(); - } catch (InterruptedException e) { - // May be a cancelled job context - } - } - } - } - } - - public ActionModeHandler( - AbstractGalleryActivity activity, SelectionManager selectionManager) { - mActivity = Utils.checkNotNull(activity); - mSelectionManager = Utils.checkNotNull(selectionManager); - mMenuExecutor = new MenuExecutor(activity, selectionManager); - mMainHandler = new Handler(activity.getMainLooper()); - mNfcAdapter = NfcAdapter.getDefaultAdapter(mActivity.getAndroidContext()); - } - - public void startActionMode() { - Activity a = mActivity; - mActionMode = a.startActionMode(this); - View customView = LayoutInflater.from(a).inflate( - R.layout.action_mode, null); - mActionMode.setCustomView(customView); - mSelectionMenu = new SelectionMenu(a, - (Button) customView.findViewById(R.id.selection_menu), this); - updateSelectionMenu(); - } - - public void finishActionMode() { - mActionMode.finish(); - } - - public void setTitle(String title) { - mSelectionMenu.setTitle(title); - } - - public void setActionModeListener(ActionModeListener listener) { - mListener = listener; - } - - private WakeLockHoldingProgressListener mDeleteProgressListener; - - @Override - public boolean onActionItemClicked(ActionMode mode, MenuItem item) { - GLRoot root = mActivity.getGLRoot(); - root.lockRenderThread(); - try { - boolean result; - // Give listener a chance to process this command before it's routed to - // ActionModeHandler, which handles command only based on the action id. - // Sometimes the listener may have more background information to handle - // an action command. - if (mListener != null) { - result = mListener.onActionItemClicked(item); - if (result) { - mSelectionManager.leaveSelectionMode(); - return result; - } - } - ProgressListener listener = null; - String confirmMsg = null; - int action = item.getItemId(); - if (action == R.id.action_delete) { - confirmMsg = mActivity.getResources().getQuantityString( - R.plurals.delete_selection, mSelectionManager.getSelectedCount()); - if (mDeleteProgressListener == null) { - mDeleteProgressListener = new WakeLockHoldingProgressListener(mActivity, - "Gallery Delete Progress Listener"); - } - listener = mDeleteProgressListener; - } - mMenuExecutor.onMenuClicked(item, confirmMsg, listener); - } finally { - root.unlockRenderThread(); - } - return true; - } - - @Override - public boolean onPopupItemClick(int itemId) { - GLRoot root = mActivity.getGLRoot(); - root.lockRenderThread(); - try { - if (itemId == R.id.action_select_all) { - updateSupportedOperation(); - mMenuExecutor.onMenuClicked(itemId, null, false, true); - } - return true; - } finally { - root.unlockRenderThread(); - } - } - - private void updateSelectionMenu() { - // update title - int count = mSelectionManager.getSelectedCount(); - String format = mActivity.getResources().getQuantityString( - R.plurals.number_of_items_selected, count); - setTitle(String.format(format, count)); - - // For clients who call SelectionManager.selectAll() directly, we need to ensure the - // menu status is consistent with selection manager. - mSelectionMenu.updateSelectAllMode(mSelectionManager.inSelectAllMode()); - } - - private final OnShareTargetSelectedListener mShareTargetSelectedListener = - new OnShareTargetSelectedListener() { - @Override - public boolean onShareTargetSelected(ShareActionProvider source, Intent intent) { - mSelectionManager.leaveSelectionMode(); - return false; - } - }; - - @Override - public boolean onPrepareActionMode(ActionMode mode, Menu menu) { - return false; - } - - @Override - public boolean onCreateActionMode(ActionMode mode, Menu menu) { - mode.getMenuInflater().inflate(R.menu.operation, menu); - - mMenu = menu; - mSharePanoramaMenuItem = menu.findItem(R.id.action_share_panorama); - if (mSharePanoramaMenuItem != null) { - mSharePanoramaActionProvider = (ShareActionProvider) mSharePanoramaMenuItem - .getActionProvider(); - mSharePanoramaActionProvider.setOnShareTargetSelectedListener( - mShareTargetSelectedListener); - mSharePanoramaActionProvider.setShareHistoryFileName("panorama_share_history.xml"); - } - mShareMenuItem = menu.findItem(R.id.action_share); - if (mShareMenuItem != null) { - mShareActionProvider = (ShareActionProvider) mShareMenuItem - .getActionProvider(); - mShareActionProvider.setOnShareTargetSelectedListener( - mShareTargetSelectedListener); - mShareActionProvider.setShareHistoryFileName("share_history.xml"); - } - return true; - } - - @Override - public void onDestroyActionMode(ActionMode mode) { - mSelectionManager.leaveSelectionMode(); - } - - private ArrayList<MediaObject> getSelectedMediaObjects(JobContext jc) { - ArrayList<Path> unexpandedPaths = mSelectionManager.getSelected(false); - if (unexpandedPaths.isEmpty()) { - // This happens when starting selection mode from overflow menu - // (instead of long press a media object) - return null; - } - ArrayList<MediaObject> selected = new ArrayList<MediaObject>(); - DataManager manager = mActivity.getDataManager(); - for (Path path : unexpandedPaths) { - if (jc.isCancelled()) { - return null; - } - selected.add(manager.getMediaObject(path)); - } - - return selected; - } - // Menu options are determined by selection set itself. - // We cannot expand it because MenuExecuter executes it based on - // the selection set instead of the expanded result. - // e.g. LocalImage can be rotated but collections of them (LocalAlbum) can't. - private int computeMenuOptions(ArrayList<MediaObject> selected) { - int operation = MediaObject.SUPPORT_ALL; - int type = 0; - for (MediaObject mediaObject: selected) { - int support = mediaObject.getSupportedOperations(); - type |= mediaObject.getMediaType(); - operation &= support; - } - - switch (selected.size()) { - case 1: - final String mimeType = MenuExecutor.getMimeType(type); - if (!GalleryUtils.isEditorAvailable(mActivity, mimeType)) { - operation &= ~MediaObject.SUPPORT_EDIT; - } - break; - default: - operation &= SUPPORT_MULTIPLE_MASK; - } - - return operation; - } - - @TargetApi(ApiHelper.VERSION_CODES.JELLY_BEAN) - private void setNfcBeamPushUris(Uri[] uris) { - if (mNfcAdapter != null && ApiHelper.HAS_SET_BEAM_PUSH_URIS) { - mNfcAdapter.setBeamPushUrisCallback(null, mActivity); - mNfcAdapter.setBeamPushUris(uris, mActivity); - } - } - - // Share intent needs to expand the selection set so we can get URI of - // each media item - private Intent computePanoramaSharingIntent(JobContext jc, int maxItems) { - ArrayList<Path> expandedPaths = mSelectionManager.getSelected(true, maxItems); - if (expandedPaths == null || expandedPaths.size() == 0) { - return new Intent(); - } - final ArrayList<Uri> uris = new ArrayList<Uri>(); - DataManager manager = mActivity.getDataManager(); - final Intent intent = new Intent(); - for (Path path : expandedPaths) { - if (jc.isCancelled()) return null; - uris.add(manager.getContentUri(path)); - } - - final int size = uris.size(); - if (size > 0) { - if (size > 1) { - intent.setAction(Intent.ACTION_SEND_MULTIPLE); - intent.setType(GalleryUtils.MIME_TYPE_PANORAMA360); - intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); - } else { - intent.setAction(Intent.ACTION_SEND); - intent.setType(GalleryUtils.MIME_TYPE_PANORAMA360); - intent.putExtra(Intent.EXTRA_STREAM, uris.get(0)); - } - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - } - - return intent; - } - - private Intent computeSharingIntent(JobContext jc, int maxItems) { - ArrayList<Path> expandedPaths = mSelectionManager.getSelected(true, maxItems); - if (expandedPaths == null || expandedPaths.size() == 0) { - setNfcBeamPushUris(null); - return new Intent(); - } - final ArrayList<Uri> uris = new ArrayList<Uri>(); - DataManager manager = mActivity.getDataManager(); - int type = 0; - final Intent intent = new Intent(); - for (Path path : expandedPaths) { - if (jc.isCancelled()) return null; - int support = manager.getSupportedOperations(path); - type |= manager.getMediaType(path); - - if ((support & MediaObject.SUPPORT_SHARE) != 0) { - uris.add(manager.getContentUri(path)); - } - } - - final int size = uris.size(); - if (size > 0) { - final String mimeType = MenuExecutor.getMimeType(type); - if (size > 1) { - intent.setAction(Intent.ACTION_SEND_MULTIPLE).setType(mimeType); - intent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uris); - } else { - intent.setAction(Intent.ACTION_SEND).setType(mimeType); - intent.putExtra(Intent.EXTRA_STREAM, uris.get(0)); - } - intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - setNfcBeamPushUris(uris.toArray(new Uri[uris.size()])); - } else { - setNfcBeamPushUris(null); - } - - return intent; - } - - public void updateSupportedOperation(Path path, boolean selected) { - // TODO: We need to improve the performance - updateSupportedOperation(); - } - - public void updateSupportedOperation() { - // Interrupt previous unfinished task, mMenuTask is only accessed in main thread - if (mMenuTask != null) mMenuTask.cancel(); - - updateSelectionMenu(); - - // Disable share actions until share intent is in good shape - if (mSharePanoramaMenuItem != null) mSharePanoramaMenuItem.setEnabled(false); - if (mShareMenuItem != null) mShareMenuItem.setEnabled(false); - - // Generate sharing intent and update supported operations in the background - // The task can take a long time and be canceled in the mean time. - mMenuTask = mActivity.getThreadPool().submit(new Job<Void>() { - @Override - public Void run(final JobContext jc) { - // Pass1: Deal with unexpanded media object list for menu operation. - ArrayList<MediaObject> selected = getSelectedMediaObjects(jc); - if (selected == null) { - mMainHandler.post(new Runnable() { - @Override - public void run() { - mMenuTask = null; - if (jc.isCancelled()) return; - // Disable all the operations when no item is selected - MenuExecutor.updateMenuOperation(mMenu, 0); - } - }); - return null; - } - final int operation = computeMenuOptions(selected); - if (jc.isCancelled()) { - return null; - } - int numSelected = selected.size(); - final boolean canSharePanoramas = - numSelected < MAX_SELECTED_ITEMS_FOR_PANORAMA_SHARE_INTENT; - final boolean canShare = - numSelected < MAX_SELECTED_ITEMS_FOR_SHARE_INTENT; - - final GetAllPanoramaSupports supportCallback = canSharePanoramas ? - new GetAllPanoramaSupports(selected, jc) - : null; - - // Pass2: Deal with expanded media object list for sharing operation. - final Intent share_panorama_intent = canSharePanoramas ? - computePanoramaSharingIntent(jc, MAX_SELECTED_ITEMS_FOR_PANORAMA_SHARE_INTENT) - : new Intent(); - final Intent share_intent = canShare ? - computeSharingIntent(jc, MAX_SELECTED_ITEMS_FOR_SHARE_INTENT) - : new Intent(); - - if (canSharePanoramas) { - supportCallback.waitForPanoramaSupport(); - } - if (jc.isCancelled()) { - return null; - } - mMainHandler.post(new Runnable() { - @Override - public void run() { - mMenuTask = null; - if (jc.isCancelled()) return; - MenuExecutor.updateMenuOperation(mMenu, operation); - MenuExecutor.updateMenuForPanorama(mMenu, - canSharePanoramas && supportCallback.mAllPanorama360, - canSharePanoramas && supportCallback.mHasPanorama360); - if (mSharePanoramaMenuItem != null) { - mSharePanoramaMenuItem.setEnabled(true); - if (canSharePanoramas && supportCallback.mAllPanorama360) { - mShareMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER); - mShareMenuItem.setTitle( - mActivity.getResources().getString(R.string.share_as_photo)); - } else { - mSharePanoramaMenuItem.setVisible(false); - mShareMenuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM); - mShareMenuItem.setTitle( - mActivity.getResources().getString(R.string.share)); - } - mSharePanoramaActionProvider.setShareIntent(share_panorama_intent); - } - if (mShareMenuItem != null) { - mShareMenuItem.setEnabled(canShare); - mShareActionProvider.setShareIntent(share_intent); - } - } - }); - return null; - } - }); - } - - public void pause() { - if (mMenuTask != null) { - mMenuTask.cancel(); - mMenuTask = null; - } - mMenuExecutor.pause(); - } - - public void destroy() { - mMenuExecutor.destroy(); - } - - public void resume() { - if (mSelectionManager.inSelectionMode()) updateSupportedOperation(); - mMenuExecutor.resume(); - } -} diff --git a/src/com/android/gallery3d/ui/AlbumLabelMaker.java b/src/com/android/gallery3d/ui/AlbumLabelMaker.java deleted file mode 100644 index da1cac0bd..000000000 --- a/src/com/android/gallery3d/ui/AlbumLabelMaker.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.PorterDuff; -import android.graphics.Typeface; -import android.text.TextPaint; -import android.text.TextUtils; - -import com.android.gallery3d.R; -import com.android.gallery3d.data.DataSourceType; -import com.android.photos.data.GalleryBitmapPool; -import com.android.gallery3d.util.ThreadPool; -import com.android.gallery3d.util.ThreadPool.JobContext; - -public class AlbumLabelMaker { - private static final int BORDER_SIZE = 0; - - private final AlbumSetSlotRenderer.LabelSpec mSpec; - private final TextPaint mTitlePaint; - private final TextPaint mCountPaint; - private final Context mContext; - - private int mLabelWidth; - private int mBitmapWidth; - private int mBitmapHeight; - - private final LazyLoadedBitmap mLocalSetIcon; - private final LazyLoadedBitmap mPicasaIcon; - private final LazyLoadedBitmap mCameraIcon; - - public AlbumLabelMaker(Context context, AlbumSetSlotRenderer.LabelSpec spec) { - mContext = context; - mSpec = spec; - mTitlePaint = getTextPaint(spec.titleFontSize, spec.titleColor, false); - mCountPaint = getTextPaint(spec.countFontSize, spec.countColor, false); - - mLocalSetIcon = new LazyLoadedBitmap(R.drawable.frame_overlay_gallery_folder); - mPicasaIcon = new LazyLoadedBitmap(R.drawable.frame_overlay_gallery_picasa); - mCameraIcon = new LazyLoadedBitmap(R.drawable.frame_overlay_gallery_camera); - } - - public static int getBorderSize() { - return BORDER_SIZE; - } - - private Bitmap getOverlayAlbumIcon(int sourceType) { - switch (sourceType) { - case DataSourceType.TYPE_CAMERA: - return mCameraIcon.get(); - case DataSourceType.TYPE_LOCAL: - return mLocalSetIcon.get(); - case DataSourceType.TYPE_PICASA: - return mPicasaIcon.get(); - } - return null; - } - - private static TextPaint getTextPaint(int textSize, int color, boolean isBold) { - TextPaint paint = new TextPaint(); - paint.setTextSize(textSize); - paint.setAntiAlias(true); - paint.setColor(color); - //paint.setShadowLayer(2f, 0f, 0f, Color.LTGRAY); - if (isBold) { - paint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD)); - } - return paint; - } - - private class LazyLoadedBitmap { - private Bitmap mBitmap; - private int mResId; - - public LazyLoadedBitmap(int resId) { - mResId = resId; - } - - public synchronized Bitmap get() { - if (mBitmap == null) { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - mBitmap = BitmapFactory.decodeResource( - mContext.getResources(), mResId, options); - } - return mBitmap; - } - } - - public synchronized void setLabelWidth(int width) { - if (mLabelWidth == width) return; - mLabelWidth = width; - int borders = 2 * BORDER_SIZE; - mBitmapWidth = width + borders; - mBitmapHeight = mSpec.labelBackgroundHeight + borders; - } - - public ThreadPool.Job<Bitmap> requestLabel( - String title, String count, int sourceType) { - return new AlbumLabelJob(title, count, sourceType); - } - - static void drawText(Canvas canvas, - int x, int y, String text, int lengthLimit, TextPaint p) { - // The TextPaint cannot be used concurrently - synchronized (p) { - text = TextUtils.ellipsize( - text, p, lengthLimit, TextUtils.TruncateAt.END).toString(); - canvas.drawText(text, x, y - p.getFontMetricsInt().ascent, p); - } - } - - private class AlbumLabelJob implements ThreadPool.Job<Bitmap> { - private final String mTitle; - private final String mCount; - private final int mSourceType; - - public AlbumLabelJob(String title, String count, int sourceType) { - mTitle = title; - mCount = count; - mSourceType = sourceType; - } - - @Override - public Bitmap run(JobContext jc) { - AlbumSetSlotRenderer.LabelSpec s = mSpec; - - String title = mTitle; - String count = mCount; - Bitmap icon = getOverlayAlbumIcon(mSourceType); - - Bitmap bitmap; - int labelWidth; - - synchronized (this) { - labelWidth = mLabelWidth; - bitmap = GalleryBitmapPool.getInstance().get(mBitmapWidth, mBitmapHeight); - } - - if (bitmap == null) { - int borders = 2 * BORDER_SIZE; - bitmap = Bitmap.createBitmap(labelWidth + borders, - s.labelBackgroundHeight + borders, Config.ARGB_8888); - } - - Canvas canvas = new Canvas(bitmap); - canvas.clipRect(BORDER_SIZE, BORDER_SIZE, - bitmap.getWidth() - BORDER_SIZE, - bitmap.getHeight() - BORDER_SIZE); - canvas.drawColor(mSpec.backgroundColor, PorterDuff.Mode.SRC); - - canvas.translate(BORDER_SIZE, BORDER_SIZE); - - // draw title - if (jc.isCancelled()) return null; - int x = s.leftMargin + s.iconSize; - // TODO: is the offset relevant in new reskin? - // int y = s.titleOffset; - int y = (s.labelBackgroundHeight - s.titleFontSize) / 2; - drawText(canvas, x, y, title, labelWidth - s.leftMargin - x - - s.titleRightMargin, mTitlePaint); - - // draw count - if (jc.isCancelled()) return null; - x = labelWidth - s.titleRightMargin; - y = (s.labelBackgroundHeight - s.countFontSize) / 2; - drawText(canvas, x, y, count, - labelWidth - x , mCountPaint); - - // draw the icon - if (icon != null) { - if (jc.isCancelled()) return null; - float scale = (float) s.iconSize / icon.getWidth(); - canvas.translate(s.leftMargin, (s.labelBackgroundHeight - - Math.round(scale * icon.getHeight()))/2f); - canvas.scale(scale, scale); - canvas.drawBitmap(icon, 0, 0, null); - } - - return bitmap; - } - } - - public void recycleLabel(Bitmap label) { - GalleryBitmapPool.getInstance().put(label); - } -} diff --git a/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java b/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java deleted file mode 100644 index 8149df4b3..000000000 --- a/src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java +++ /dev/null @@ -1,549 +0,0 @@ -/*T - * 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.ui; - -import android.graphics.Bitmap; -import android.os.Message; - -import com.android.gallery3d.R; -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.app.AlbumSetDataLoader; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.DataSourceType; -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.glrenderer.BitmapTexture; -import com.android.gallery3d.glrenderer.Texture; -import com.android.gallery3d.glrenderer.TextureUploader; -import com.android.gallery3d.glrenderer.TiledTexture; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.FutureListener; -import com.android.gallery3d.util.ThreadPool; - -public class AlbumSetSlidingWindow implements AlbumSetDataLoader.DataListener { - private static final String TAG = "AlbumSetSlidingWindow"; - private static final int MSG_UPDATE_ALBUM_ENTRY = 1; - - public static interface Listener { - public void onSizeChanged(int size); - public void onContentChanged(); - } - - private final AlbumSetDataLoader mSource; - private int mSize; - - private int mContentStart = 0; - private int mContentEnd = 0; - - private int mActiveStart = 0; - private int mActiveEnd = 0; - - private Listener mListener; - - private final AlbumSetEntry mData[]; - private final SynchronizedHandler mHandler; - private final ThreadPool mThreadPool; - private final AlbumLabelMaker mLabelMaker; - private final String mLoadingText; - - private final TiledTexture.Uploader mContentUploader; - private final TextureUploader mLabelUploader; - - private int mActiveRequestCount = 0; - private boolean mIsActive = false; - private BitmapTexture mLoadingLabel; - - private int mSlotWidth; - - public static class AlbumSetEntry { - public MediaSet album; - public MediaItem coverItem; - public Texture content; - public BitmapTexture labelTexture; - public TiledTexture bitmapTexture; - public Path setPath; - public String title; - public int totalCount; - public int sourceType; - public int cacheFlag; - public int cacheStatus; - public int rotation; - public boolean isWaitLoadingDisplayed; - public long setDataVersion; - public long coverDataVersion; - private BitmapLoader labelLoader; - private BitmapLoader coverLoader; - } - - public AlbumSetSlidingWindow(AbstractGalleryActivity activity, - AlbumSetDataLoader source, AlbumSetSlotRenderer.LabelSpec labelSpec, int cacheSize) { - source.setModelListener(this); - mSource = source; - mData = new AlbumSetEntry[cacheSize]; - mSize = source.size(); - mThreadPool = activity.getThreadPool(); - - mLabelMaker = new AlbumLabelMaker(activity.getAndroidContext(), labelSpec); - mLoadingText = activity.getAndroidContext().getString(R.string.loading); - mContentUploader = new TiledTexture.Uploader(activity.getGLRoot()); - mLabelUploader = new TextureUploader(activity.getGLRoot()); - - mHandler = new SynchronizedHandler(activity.getGLRoot()) { - @Override - public void handleMessage(Message message) { - Utils.assertTrue(message.what == MSG_UPDATE_ALBUM_ENTRY); - ((EntryUpdater) message.obj).updateEntry(); - } - }; - } - - public void setListener(Listener listener) { - mListener = listener; - } - - public AlbumSetEntry get(int slotIndex) { - if (!isActiveSlot(slotIndex)) { - Utils.fail("invalid slot: %s outsides (%s, %s)", - slotIndex, mActiveStart, mActiveEnd); - } - return mData[slotIndex % mData.length]; - } - - public int size() { - return mSize; - } - - public boolean isActiveSlot(int slotIndex) { - return slotIndex >= mActiveStart && slotIndex < mActiveEnd; - } - - private void setContentWindow(int contentStart, int contentEnd) { - if (contentStart == mContentStart && contentEnd == mContentEnd) return; - - if (contentStart >= mContentEnd || mContentStart >= contentEnd) { - for (int i = mContentStart, n = mContentEnd; i < n; ++i) { - freeSlotContent(i); - } - mSource.setActiveWindow(contentStart, contentEnd); - for (int i = contentStart; i < contentEnd; ++i) { - prepareSlotContent(i); - } - } else { - for (int i = mContentStart; i < contentStart; ++i) { - freeSlotContent(i); - } - for (int i = contentEnd, n = mContentEnd; i < n; ++i) { - freeSlotContent(i); - } - mSource.setActiveWindow(contentStart, contentEnd); - for (int i = contentStart, n = mContentStart; i < n; ++i) { - prepareSlotContent(i); - } - for (int i = mContentEnd; i < contentEnd; ++i) { - prepareSlotContent(i); - } - } - - mContentStart = contentStart; - mContentEnd = contentEnd; - } - - public void setActiveWindow(int start, int end) { - if (!(start <= end && end - start <= mData.length && end <= mSize)) { - Utils.fail("start = %s, end = %s, length = %s, size = %s", - start, end, mData.length, mSize); - } - - AlbumSetEntry data[] = mData; - mActiveStart = start; - mActiveEnd = end; - int contentStart = Utils.clamp((start + end) / 2 - data.length / 2, - 0, Math.max(0, mSize - data.length)); - int contentEnd = Math.min(contentStart + data.length, mSize); - setContentWindow(contentStart, contentEnd); - - if (mIsActive) { - updateTextureUploadQueue(); - updateAllImageRequests(); - } - } - - // We would like to request non active slots in the following order: - // Order: 8 6 4 2 1 3 5 7 - // |---------|---------------|---------| - // |<- active ->| - // |<-------- cached range ----------->| - private void requestNonactiveImages() { - int range = Math.max( - mContentEnd - mActiveEnd, mActiveStart - mContentStart); - for (int i = 0 ;i < range; ++i) { - requestImagesInSlot(mActiveEnd + i); - requestImagesInSlot(mActiveStart - 1 - i); - } - } - - private void cancelNonactiveImages() { - int range = Math.max( - mContentEnd - mActiveEnd, mActiveStart - mContentStart); - for (int i = 0 ;i < range; ++i) { - cancelImagesInSlot(mActiveEnd + i); - cancelImagesInSlot(mActiveStart - 1 - i); - } - } - - private void requestImagesInSlot(int slotIndex) { - if (slotIndex < mContentStart || slotIndex >= mContentEnd) return; - AlbumSetEntry entry = mData[slotIndex % mData.length]; - if (entry.coverLoader != null) entry.coverLoader.startLoad(); - if (entry.labelLoader != null) entry.labelLoader.startLoad(); - } - - private void cancelImagesInSlot(int slotIndex) { - if (slotIndex < mContentStart || slotIndex >= mContentEnd) return; - AlbumSetEntry entry = mData[slotIndex % mData.length]; - if (entry.coverLoader != null) entry.coverLoader.cancelLoad(); - if (entry.labelLoader != null) entry.labelLoader.cancelLoad(); - } - - private static long getDataVersion(MediaObject object) { - return object == null - ? MediaSet.INVALID_DATA_VERSION - : object.getDataVersion(); - } - - private void freeSlotContent(int slotIndex) { - AlbumSetEntry entry = mData[slotIndex % mData.length]; - if (entry.coverLoader != null) entry.coverLoader.recycle(); - if (entry.labelLoader != null) entry.labelLoader.recycle(); - if (entry.labelTexture != null) entry.labelTexture.recycle(); - if (entry.bitmapTexture != null) entry.bitmapTexture.recycle(); - mData[slotIndex % mData.length] = null; - } - - private boolean isLabelChanged( - AlbumSetEntry entry, String title, int totalCount, int sourceType) { - return !Utils.equals(entry.title, title) - || entry.totalCount != totalCount - || entry.sourceType != sourceType; - } - - private void updateAlbumSetEntry(AlbumSetEntry entry, int slotIndex) { - MediaSet album = mSource.getMediaSet(slotIndex); - MediaItem cover = mSource.getCoverItem(slotIndex); - int totalCount = mSource.getTotalCount(slotIndex); - - entry.album = album; - entry.setDataVersion = getDataVersion(album); - entry.cacheFlag = identifyCacheFlag(album); - entry.cacheStatus = identifyCacheStatus(album); - entry.setPath = (album == null) ? null : album.getPath(); - - String title = (album == null) ? "" : Utils.ensureNotNull(album.getName()); - int sourceType = DataSourceType.identifySourceType(album); - if (isLabelChanged(entry, title, totalCount, sourceType)) { - entry.title = title; - entry.totalCount = totalCount; - entry.sourceType = sourceType; - if (entry.labelLoader != null) { - entry.labelLoader.recycle(); - entry.labelLoader = null; - entry.labelTexture = null; - } - if (album != null) { - entry.labelLoader = new AlbumLabelLoader( - slotIndex, title, totalCount, sourceType); - } - } - - entry.coverItem = cover; - if (getDataVersion(cover) != entry.coverDataVersion) { - entry.coverDataVersion = getDataVersion(cover); - entry.rotation = (cover == null) ? 0 : cover.getRotation(); - if (entry.coverLoader != null) { - entry.coverLoader.recycle(); - entry.coverLoader = null; - entry.bitmapTexture = null; - entry.content = null; - } - if (cover != null) { - entry.coverLoader = new AlbumCoverLoader(slotIndex, cover); - } - } - } - - private void prepareSlotContent(int slotIndex) { - AlbumSetEntry entry = new AlbumSetEntry(); - updateAlbumSetEntry(entry, slotIndex); - mData[slotIndex % mData.length] = entry; - } - - private static boolean startLoadBitmap(BitmapLoader loader) { - if (loader == null) return false; - loader.startLoad(); - return loader.isRequestInProgress(); - } - - private void uploadBackgroundTextureInSlot(int index) { - if (index < mContentStart || index >= mContentEnd) return; - AlbumSetEntry entry = mData[index % mData.length]; - if (entry.bitmapTexture != null) { - mContentUploader.addTexture(entry.bitmapTexture); - } - if (entry.labelTexture != null) { - mLabelUploader.addBgTexture(entry.labelTexture); - } - } - - private void updateTextureUploadQueue() { - if (!mIsActive) return; - mContentUploader.clear(); - mLabelUploader.clear(); - - // Upload foreground texture - for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) { - AlbumSetEntry entry = mData[i % mData.length]; - if (entry.bitmapTexture != null) { - mContentUploader.addTexture(entry.bitmapTexture); - } - if (entry.labelTexture != null) { - mLabelUploader.addFgTexture(entry.labelTexture); - } - } - - // add background textures - int range = Math.max( - (mContentEnd - mActiveEnd), (mActiveStart - mContentStart)); - for (int i = 0; i < range; ++i) { - uploadBackgroundTextureInSlot(mActiveEnd + i); - uploadBackgroundTextureInSlot(mActiveStart - i - 1); - } - } - - private void updateAllImageRequests() { - mActiveRequestCount = 0; - for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) { - AlbumSetEntry entry = mData[i % mData.length]; - if (startLoadBitmap(entry.coverLoader)) ++mActiveRequestCount; - if (startLoadBitmap(entry.labelLoader)) ++mActiveRequestCount; - } - if (mActiveRequestCount == 0) { - requestNonactiveImages(); - } else { - cancelNonactiveImages(); - } - } - - @Override - public void onSizeChanged(int size) { - if (mIsActive && mSize != size) { - mSize = size; - if (mListener != null) mListener.onSizeChanged(mSize); - if (mContentEnd > mSize) mContentEnd = mSize; - if (mActiveEnd > mSize) mActiveEnd = mSize; - } - } - - @Override - public void onContentChanged(int index) { - if (!mIsActive) { - // paused, ignore slot changed event - return; - } - - // If the updated content is not cached, ignore it - if (index < mContentStart || index >= mContentEnd) { - Log.w(TAG, String.format( - "invalid update: %s is outside (%s, %s)", - index, mContentStart, mContentEnd) ); - return; - } - - AlbumSetEntry entry = mData[index % mData.length]; - updateAlbumSetEntry(entry, index); - updateAllImageRequests(); - updateTextureUploadQueue(); - if (mListener != null && isActiveSlot(index)) { - mListener.onContentChanged(); - } - } - - public BitmapTexture getLoadingTexture() { - if (mLoadingLabel == null) { - Bitmap bitmap = mLabelMaker.requestLabel( - mLoadingText, "", DataSourceType.TYPE_NOT_CATEGORIZED) - .run(ThreadPool.JOB_CONTEXT_STUB); - mLoadingLabel = new BitmapTexture(bitmap); - mLoadingLabel.setOpaque(false); - } - return mLoadingLabel; - } - - public void pause() { - mIsActive = false; - mLabelUploader.clear(); - mContentUploader.clear(); - TiledTexture.freeResources(); - for (int i = mContentStart, n = mContentEnd; i < n; ++i) { - freeSlotContent(i); - } - } - - public void resume() { - mIsActive = true; - TiledTexture.prepareResources(); - for (int i = mContentStart, n = mContentEnd; i < n; ++i) { - prepareSlotContent(i); - } - updateAllImageRequests(); - } - - private static interface EntryUpdater { - public void updateEntry(); - } - - private class AlbumCoverLoader extends BitmapLoader implements EntryUpdater { - private MediaItem mMediaItem; - private final int mSlotIndex; - - public AlbumCoverLoader(int slotIndex, MediaItem item) { - mSlotIndex = slotIndex; - mMediaItem = item; - } - - @Override - protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) { - return mThreadPool.submit(mMediaItem.requestImage( - MediaItem.TYPE_MICROTHUMBNAIL), l); - } - - @Override - protected void onLoadComplete(Bitmap bitmap) { - mHandler.obtainMessage(MSG_UPDATE_ALBUM_ENTRY, this).sendToTarget(); - } - - @Override - public void updateEntry() { - Bitmap bitmap = getBitmap(); - if (bitmap == null) return; // error or recycled - - AlbumSetEntry entry = mData[mSlotIndex % mData.length]; - TiledTexture texture = new TiledTexture(bitmap); - entry.bitmapTexture = texture; - entry.content = texture; - - if (isActiveSlot(mSlotIndex)) { - mContentUploader.addTexture(texture); - --mActiveRequestCount; - if (mActiveRequestCount == 0) requestNonactiveImages(); - if (mListener != null) mListener.onContentChanged(); - } else { - mContentUploader.addTexture(texture); - } - } - } - - private static int identifyCacheFlag(MediaSet set) { - if (set == null || (set.getSupportedOperations() - & MediaSet.SUPPORT_CACHE) == 0) { - return MediaSet.CACHE_FLAG_NO; - } - - return set.getCacheFlag(); - } - - private static int identifyCacheStatus(MediaSet set) { - if (set == null || (set.getSupportedOperations() - & MediaSet.SUPPORT_CACHE) == 0) { - return MediaSet.CACHE_STATUS_NOT_CACHED; - } - - return set.getCacheStatus(); - } - - private class AlbumLabelLoader extends BitmapLoader implements EntryUpdater { - private final int mSlotIndex; - private final String mTitle; - private final int mTotalCount; - private final int mSourceType; - - public AlbumLabelLoader( - int slotIndex, String title, int totalCount, int sourceType) { - mSlotIndex = slotIndex; - mTitle = title; - mTotalCount = totalCount; - mSourceType = sourceType; - } - - @Override - protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) { - return mThreadPool.submit(mLabelMaker.requestLabel( - mTitle, String.valueOf(mTotalCount), mSourceType), l); - } - - @Override - protected void onLoadComplete(Bitmap bitmap) { - mHandler.obtainMessage(MSG_UPDATE_ALBUM_ENTRY, this).sendToTarget(); - } - - @Override - public void updateEntry() { - Bitmap bitmap = getBitmap(); - if (bitmap == null) return; // Error or recycled - - AlbumSetEntry entry = mData[mSlotIndex % mData.length]; - BitmapTexture texture = new BitmapTexture(bitmap); - texture.setOpaque(false); - entry.labelTexture = texture; - - if (isActiveSlot(mSlotIndex)) { - mLabelUploader.addFgTexture(texture); - --mActiveRequestCount; - if (mActiveRequestCount == 0) requestNonactiveImages(); - if (mListener != null) mListener.onContentChanged(); - } else { - mLabelUploader.addBgTexture(texture); - } - } - } - - public void onSlotSizeChanged(int width, int height) { - if (mSlotWidth == width) return; - - mSlotWidth = width; - mLoadingLabel = null; - mLabelMaker.setLabelWidth(mSlotWidth); - - if (!mIsActive) return; - - for (int i = mContentStart, n = mContentEnd; i < n; ++i) { - AlbumSetEntry entry = mData[i % mData.length]; - if (entry.labelLoader != null) { - entry.labelLoader.recycle(); - entry.labelLoader = null; - entry.labelTexture = null; - } - if (entry.album != null) { - entry.labelLoader = new AlbumLabelLoader(i, - entry.title, entry.totalCount, entry.sourceType); - } - } - updateAllImageRequests(); - updateTextureUploadQueue(); - } -} diff --git a/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java b/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java deleted file mode 100644 index 5332ef89a..000000000 --- a/src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java +++ /dev/null @@ -1,242 +0,0 @@ -/* - * 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.ui; - -import com.android.gallery3d.R; -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.app.AlbumSetDataLoader; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.glrenderer.ColorTexture; -import com.android.gallery3d.glrenderer.FadeInTexture; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.ResourceTexture; -import com.android.gallery3d.glrenderer.Texture; -import com.android.gallery3d.glrenderer.TiledTexture; -import com.android.gallery3d.glrenderer.UploadedTexture; -import com.android.gallery3d.ui.AlbumSetSlidingWindow.AlbumSetEntry; - -public class AlbumSetSlotRenderer extends AbstractSlotRenderer { - @SuppressWarnings("unused") - private static final String TAG = "AlbumSetView"; - private static final int CACHE_SIZE = 96; - private final int mPlaceholderColor; - - private final ColorTexture mWaitLoadingTexture; - private final ResourceTexture mCameraOverlay; - private final AbstractGalleryActivity mActivity; - private final SelectionManager mSelectionManager; - protected final LabelSpec mLabelSpec; - - protected AlbumSetSlidingWindow mDataWindow; - private SlotView mSlotView; - - private int mPressedIndex = -1; - private boolean mAnimatePressedUp; - private Path mHighlightItemPath = null; - private boolean mInSelectionMode; - - public static class LabelSpec { - public int labelBackgroundHeight; - public int titleOffset; - public int countOffset; - public int titleFontSize; - public int countFontSize; - public int leftMargin; - public int iconSize; - public int titleRightMargin; - public int backgroundColor; - public int titleColor; - public int countColor; - public int borderSize; - } - - public AlbumSetSlotRenderer(AbstractGalleryActivity activity, - SelectionManager selectionManager, - SlotView slotView, LabelSpec labelSpec, int placeholderColor) { - super (activity); - mActivity = activity; - mSelectionManager = selectionManager; - mSlotView = slotView; - mLabelSpec = labelSpec; - mPlaceholderColor = placeholderColor; - - mWaitLoadingTexture = new ColorTexture(mPlaceholderColor); - mWaitLoadingTexture.setSize(1, 1); - mCameraOverlay = new ResourceTexture(activity, - R.drawable.ic_cameraalbum_overlay); - } - - public void setPressedIndex(int index) { - if (mPressedIndex == index) return; - mPressedIndex = index; - mSlotView.invalidate(); - } - - public void setPressedUp() { - if (mPressedIndex == -1) return; - mAnimatePressedUp = true; - mSlotView.invalidate(); - } - - public void setHighlightItemPath(Path path) { - if (mHighlightItemPath == path) return; - mHighlightItemPath = path; - mSlotView.invalidate(); - } - - public void setModel(AlbumSetDataLoader model) { - if (mDataWindow != null) { - mDataWindow.setListener(null); - mDataWindow = null; - mSlotView.setSlotCount(0); - } - if (model != null) { - mDataWindow = new AlbumSetSlidingWindow( - mActivity, model, mLabelSpec, CACHE_SIZE); - mDataWindow.setListener(new MyCacheListener()); - mSlotView.setSlotCount(mDataWindow.size()); - } - } - - private static Texture checkLabelTexture(Texture texture) { - return ((texture instanceof UploadedTexture) - && ((UploadedTexture) texture).isUploading()) - ? null - : texture; - } - - private static Texture checkContentTexture(Texture texture) { - return ((texture instanceof TiledTexture) - && !((TiledTexture) texture).isReady()) - ? null - : texture; - } - - @Override - public int renderSlot(GLCanvas canvas, int index, int pass, int width, int height) { - AlbumSetEntry entry = mDataWindow.get(index); - int renderRequestFlags = 0; - renderRequestFlags |= renderContent(canvas, entry, width, height); - renderRequestFlags |= renderLabel(canvas, entry, width, height); - renderRequestFlags |= renderOverlay(canvas, index, entry, width, height); - return renderRequestFlags; - } - - protected int renderOverlay( - GLCanvas canvas, int index, AlbumSetEntry entry, int width, int height) { - int renderRequestFlags = 0; - if (entry.album != null && entry.album.isCameraRoll()) { - int uncoveredHeight = height - mLabelSpec.labelBackgroundHeight; - int dim = uncoveredHeight / 2; - mCameraOverlay.draw(canvas, (width - dim) / 2, - (uncoveredHeight - dim) / 2, dim, dim); - } - if (mPressedIndex == index) { - if (mAnimatePressedUp) { - drawPressedUpFrame(canvas, width, height); - renderRequestFlags |= SlotView.RENDER_MORE_FRAME; - if (isPressedUpFrameFinished()) { - mAnimatePressedUp = false; - mPressedIndex = -1; - } - } else { - drawPressedFrame(canvas, width, height); - } - } else if ((mHighlightItemPath != null) && (mHighlightItemPath == entry.setPath)) { - drawSelectedFrame(canvas, width, height); - } else if (mInSelectionMode && mSelectionManager.isItemSelected(entry.setPath)) { - drawSelectedFrame(canvas, width, height); - } - return renderRequestFlags; - } - - protected int renderContent( - GLCanvas canvas, AlbumSetEntry entry, int width, int height) { - int renderRequestFlags = 0; - - Texture content = checkContentTexture(entry.content); - if (content == null) { - content = mWaitLoadingTexture; - entry.isWaitLoadingDisplayed = true; - } else if (entry.isWaitLoadingDisplayed) { - entry.isWaitLoadingDisplayed = false; - content = new FadeInTexture(mPlaceholderColor, entry.bitmapTexture); - entry.content = content; - } - drawContent(canvas, content, width, height, entry.rotation); - if ((content instanceof FadeInTexture) && - ((FadeInTexture) content).isAnimating()) { - renderRequestFlags |= SlotView.RENDER_MORE_FRAME; - } - - return renderRequestFlags; - } - - protected int renderLabel( - GLCanvas canvas, AlbumSetEntry entry, int width, int height) { - Texture content = checkLabelTexture(entry.labelTexture); - if (content == null) { - content = mWaitLoadingTexture; - } - int b = AlbumLabelMaker.getBorderSize(); - int h = mLabelSpec.labelBackgroundHeight; - content.draw(canvas, -b, height - h + b, width + b + b, h); - - return 0; - } - - @Override - public void prepareDrawing() { - mInSelectionMode = mSelectionManager.inSelectionMode(); - } - - private class MyCacheListener implements AlbumSetSlidingWindow.Listener { - - @Override - public void onSizeChanged(int size) { - mSlotView.setSlotCount(size); - } - - @Override - public void onContentChanged() { - mSlotView.invalidate(); - } - } - - public void pause() { - mDataWindow.pause(); - } - - public void resume() { - mDataWindow.resume(); - } - - @Override - public void onVisibleRangeChanged(int visibleStart, int visibleEnd) { - if (mDataWindow != null) { - mDataWindow.setActiveWindow(visibleStart, visibleEnd); - } - } - - @Override - public void onSlotSizeChanged(int width, int height) { - if (mDataWindow != null) { - mDataWindow.onSlotSizeChanged(width, height); - } - } -} diff --git a/src/com/android/gallery3d/ui/AlbumSlidingWindow.java b/src/com/android/gallery3d/ui/AlbumSlidingWindow.java deleted file mode 100644 index fec7d1e92..000000000 --- a/src/com/android/gallery3d/ui/AlbumSlidingWindow.java +++ /dev/null @@ -1,365 +0,0 @@ -/* - * 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.ui; - -import android.graphics.Bitmap; -import android.os.Message; - -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.app.AlbumDataLoader; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.MediaObject.PanoramaSupportCallback; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.glrenderer.Texture; -import com.android.gallery3d.glrenderer.TiledTexture; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.FutureListener; -import com.android.gallery3d.util.JobLimiter; - -public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { - @SuppressWarnings("unused") - private static final String TAG = "AlbumSlidingWindow"; - - private static final int MSG_UPDATE_ENTRY = 0; - private static final int JOB_LIMIT = 2; - - public static interface Listener { - public void onSizeChanged(int size); - public void onContentChanged(); - } - - public static class AlbumEntry { - public MediaItem item; - public Path path; - public boolean isPanorama; - public int rotation; - public int mediaType; - public boolean isWaitDisplayed; - public TiledTexture bitmapTexture; - public Texture content; - private BitmapLoader contentLoader; - private PanoSupportListener mPanoSupportListener; - } - - private final AlbumDataLoader mSource; - private final AlbumEntry mData[]; - private final SynchronizedHandler mHandler; - private final JobLimiter mThreadPool; - private final TiledTexture.Uploader mTileUploader; - - private int mSize; - - private int mContentStart = 0; - private int mContentEnd = 0; - - private int mActiveStart = 0; - private int mActiveEnd = 0; - - private Listener mListener; - - private int mActiveRequestCount = 0; - private boolean mIsActive = false; - - private class PanoSupportListener implements PanoramaSupportCallback { - public final AlbumEntry mEntry; - public PanoSupportListener (AlbumEntry entry) { - mEntry = entry; - } - @Override - public void panoramaInfoAvailable(MediaObject mediaObject, boolean isPanorama, - boolean isPanorama360) { - if (mEntry != null) mEntry.isPanorama = isPanorama; - } - } - - public AlbumSlidingWindow(AbstractGalleryActivity activity, - AlbumDataLoader source, int cacheSize) { - source.setDataListener(this); - mSource = source; - mData = new AlbumEntry[cacheSize]; - mSize = source.size(); - - mHandler = new SynchronizedHandler(activity.getGLRoot()) { - @Override - public void handleMessage(Message message) { - Utils.assertTrue(message.what == MSG_UPDATE_ENTRY); - ((ThumbnailLoader) message.obj).updateEntry(); - } - }; - - mThreadPool = new JobLimiter(activity.getThreadPool(), JOB_LIMIT); - mTileUploader = new TiledTexture.Uploader(activity.getGLRoot()); - } - - public void setListener(Listener listener) { - mListener = listener; - } - - public AlbumEntry get(int slotIndex) { - if (!isActiveSlot(slotIndex)) { - Utils.fail("invalid slot: %s outsides (%s, %s)", - slotIndex, mActiveStart, mActiveEnd); - } - return mData[slotIndex % mData.length]; - } - - public boolean isActiveSlot(int slotIndex) { - return slotIndex >= mActiveStart && slotIndex < mActiveEnd; - } - - private void setContentWindow(int contentStart, int contentEnd) { - if (contentStart == mContentStart && contentEnd == mContentEnd) return; - - if (!mIsActive) { - mContentStart = contentStart; - mContentEnd = contentEnd; - mSource.setActiveWindow(contentStart, contentEnd); - return; - } - - if (contentStart >= mContentEnd || mContentStart >= contentEnd) { - for (int i = mContentStart, n = mContentEnd; i < n; ++i) { - freeSlotContent(i); - } - mSource.setActiveWindow(contentStart, contentEnd); - for (int i = contentStart; i < contentEnd; ++i) { - prepareSlotContent(i); - } - } else { - for (int i = mContentStart; i < contentStart; ++i) { - freeSlotContent(i); - } - for (int i = contentEnd, n = mContentEnd; i < n; ++i) { - freeSlotContent(i); - } - mSource.setActiveWindow(contentStart, contentEnd); - for (int i = contentStart, n = mContentStart; i < n; ++i) { - prepareSlotContent(i); - } - for (int i = mContentEnd; i < contentEnd; ++i) { - prepareSlotContent(i); - } - } - - mContentStart = contentStart; - mContentEnd = contentEnd; - } - - public void setActiveWindow(int start, int end) { - if (!(start <= end && end - start <= mData.length && end <= mSize)) { - Utils.fail("%s, %s, %s, %s", start, end, mData.length, mSize); - } - AlbumEntry data[] = mData; - - mActiveStart = start; - mActiveEnd = end; - - int contentStart = Utils.clamp((start + end) / 2 - data.length / 2, - 0, Math.max(0, mSize - data.length)); - int contentEnd = Math.min(contentStart + data.length, mSize); - setContentWindow(contentStart, contentEnd); - updateTextureUploadQueue(); - if (mIsActive) updateAllImageRequests(); - } - - private void uploadBgTextureInSlot(int index) { - if (index < mContentEnd && index >= mContentStart) { - AlbumEntry entry = mData[index % mData.length]; - if (entry.bitmapTexture != null) { - mTileUploader.addTexture(entry.bitmapTexture); - } - } - } - - private void updateTextureUploadQueue() { - if (!mIsActive) return; - mTileUploader.clear(); - - // add foreground textures - for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) { - AlbumEntry entry = mData[i % mData.length]; - if (entry.bitmapTexture != null) { - mTileUploader.addTexture(entry.bitmapTexture); - } - } - - // add background textures - int range = Math.max( - (mContentEnd - mActiveEnd), (mActiveStart - mContentStart)); - for (int i = 0; i < range; ++i) { - uploadBgTextureInSlot(mActiveEnd + i); - uploadBgTextureInSlot(mActiveStart - i - 1); - } - } - - // We would like to request non active slots in the following order: - // Order: 8 6 4 2 1 3 5 7 - // |---------|---------------|---------| - // |<- active ->| - // |<-------- cached range ----------->| - private void requestNonactiveImages() { - int range = Math.max( - (mContentEnd - mActiveEnd), (mActiveStart - mContentStart)); - for (int i = 0 ;i < range; ++i) { - requestSlotImage(mActiveEnd + i); - requestSlotImage(mActiveStart - 1 - i); - } - } - - // return whether the request is in progress or not - private boolean requestSlotImage(int slotIndex) { - if (slotIndex < mContentStart || slotIndex >= mContentEnd) return false; - AlbumEntry entry = mData[slotIndex % mData.length]; - if (entry.content != null || entry.item == null) return false; - - // Set up the panorama callback - entry.mPanoSupportListener = new PanoSupportListener(entry); - entry.item.getPanoramaSupport(entry.mPanoSupportListener); - - entry.contentLoader.startLoad(); - return entry.contentLoader.isRequestInProgress(); - } - - private void cancelNonactiveImages() { - int range = Math.max( - (mContentEnd - mActiveEnd), (mActiveStart - mContentStart)); - for (int i = 0 ;i < range; ++i) { - cancelSlotImage(mActiveEnd + i); - cancelSlotImage(mActiveStart - 1 - i); - } - } - - private void cancelSlotImage(int slotIndex) { - if (slotIndex < mContentStart || slotIndex >= mContentEnd) return; - AlbumEntry item = mData[slotIndex % mData.length]; - if (item.contentLoader != null) item.contentLoader.cancelLoad(); - } - - private void freeSlotContent(int slotIndex) { - AlbumEntry data[] = mData; - int index = slotIndex % data.length; - AlbumEntry entry = data[index]; - if (entry.contentLoader != null) entry.contentLoader.recycle(); - if (entry.bitmapTexture != null) entry.bitmapTexture.recycle(); - data[index] = null; - } - - private void prepareSlotContent(int slotIndex) { - AlbumEntry entry = new AlbumEntry(); - MediaItem item = mSource.get(slotIndex); // item could be null; - entry.item = item; - entry.mediaType = (item == null) - ? MediaItem.MEDIA_TYPE_UNKNOWN - : entry.item.getMediaType(); - entry.path = (item == null) ? null : item.getPath(); - entry.rotation = (item == null) ? 0 : item.getRotation(); - entry.contentLoader = new ThumbnailLoader(slotIndex, entry.item); - mData[slotIndex % mData.length] = entry; - } - - private void updateAllImageRequests() { - mActiveRequestCount = 0; - for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) { - if (requestSlotImage(i)) ++mActiveRequestCount; - } - if (mActiveRequestCount == 0) { - requestNonactiveImages(); - } else { - cancelNonactiveImages(); - } - } - - private class ThumbnailLoader extends BitmapLoader { - private final int mSlotIndex; - private final MediaItem mItem; - - public ThumbnailLoader(int slotIndex, MediaItem item) { - mSlotIndex = slotIndex; - mItem = item; - } - - @Override - protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) { - return mThreadPool.submit( - mItem.requestImage(MediaItem.TYPE_MICROTHUMBNAIL), this); - } - - @Override - protected void onLoadComplete(Bitmap bitmap) { - mHandler.obtainMessage(MSG_UPDATE_ENTRY, this).sendToTarget(); - } - - public void updateEntry() { - Bitmap bitmap = getBitmap(); - if (bitmap == null) return; // error or recycled - AlbumEntry entry = mData[mSlotIndex % mData.length]; - entry.bitmapTexture = new TiledTexture(bitmap); - entry.content = entry.bitmapTexture; - - if (isActiveSlot(mSlotIndex)) { - mTileUploader.addTexture(entry.bitmapTexture); - --mActiveRequestCount; - if (mActiveRequestCount == 0) requestNonactiveImages(); - if (mListener != null) mListener.onContentChanged(); - } else { - mTileUploader.addTexture(entry.bitmapTexture); - } - } - } - - @Override - public void onSizeChanged(int size) { - if (mSize != size) { - mSize = size; - if (mListener != null) mListener.onSizeChanged(mSize); - if (mContentEnd > mSize) mContentEnd = mSize; - if (mActiveEnd > mSize) mActiveEnd = mSize; - } - } - - @Override - public void onContentChanged(int index) { - if (index >= mContentStart && index < mContentEnd && mIsActive) { - freeSlotContent(index); - prepareSlotContent(index); - updateAllImageRequests(); - if (mListener != null && isActiveSlot(index)) { - mListener.onContentChanged(); - } - } - } - - public void resume() { - mIsActive = true; - TiledTexture.prepareResources(); - for (int i = mContentStart, n = mContentEnd; i < n; ++i) { - prepareSlotContent(i); - } - updateAllImageRequests(); - } - - public void pause() { - mIsActive = false; - mTileUploader.clear(); - TiledTexture.freeResources(); - for (int i = mContentStart, n = mContentEnd; i < n; ++i) { - freeSlotContent(i); - } - } -} diff --git a/src/com/android/gallery3d/ui/AlbumSlotRenderer.java b/src/com/android/gallery3d/ui/AlbumSlotRenderer.java deleted file mode 100644 index dc6c89b0e..000000000 --- a/src/com/android/gallery3d/ui/AlbumSlotRenderer.java +++ /dev/null @@ -1,201 +0,0 @@ -/* - * 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.ui; - -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.app.AlbumDataLoader; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.glrenderer.ColorTexture; -import com.android.gallery3d.glrenderer.FadeInTexture; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.Texture; -import com.android.gallery3d.glrenderer.TiledTexture; - -public class AlbumSlotRenderer extends AbstractSlotRenderer { - @SuppressWarnings("unused") - private static final String TAG = "AlbumView"; - - public interface SlotFilter { - public boolean acceptSlot(int index); - } - - private final int mPlaceholderColor; - private static final int CACHE_SIZE = 96; - - private AlbumSlidingWindow mDataWindow; - private final AbstractGalleryActivity mActivity; - private final ColorTexture mWaitLoadingTexture; - private final SlotView mSlotView; - private final SelectionManager mSelectionManager; - - private int mPressedIndex = -1; - private boolean mAnimatePressedUp; - private Path mHighlightItemPath = null; - private boolean mInSelectionMode; - - private SlotFilter mSlotFilter; - - public AlbumSlotRenderer(AbstractGalleryActivity activity, SlotView slotView, - SelectionManager selectionManager, int placeholderColor) { - super(activity); - mActivity = activity; - mSlotView = slotView; - mSelectionManager = selectionManager; - mPlaceholderColor = placeholderColor; - - mWaitLoadingTexture = new ColorTexture(mPlaceholderColor); - mWaitLoadingTexture.setSize(1, 1); - } - - public void setPressedIndex(int index) { - if (mPressedIndex == index) return; - mPressedIndex = index; - mSlotView.invalidate(); - } - - public void setPressedUp() { - if (mPressedIndex == -1) return; - mAnimatePressedUp = true; - mSlotView.invalidate(); - } - - public void setHighlightItemPath(Path path) { - if (mHighlightItemPath == path) return; - mHighlightItemPath = path; - mSlotView.invalidate(); - } - - public void setModel(AlbumDataLoader model) { - if (mDataWindow != null) { - mDataWindow.setListener(null); - mSlotView.setSlotCount(0); - mDataWindow = null; - } - if (model != null) { - mDataWindow = new AlbumSlidingWindow(mActivity, model, CACHE_SIZE); - mDataWindow.setListener(new MyDataModelListener()); - mSlotView.setSlotCount(model.size()); - } - } - - private static Texture checkTexture(Texture texture) { - return (texture instanceof TiledTexture) - && !((TiledTexture) texture).isReady() - ? null - : texture; - } - - @Override - public int renderSlot(GLCanvas canvas, int index, int pass, int width, int height) { - if (mSlotFilter != null && !mSlotFilter.acceptSlot(index)) return 0; - - AlbumSlidingWindow.AlbumEntry entry = mDataWindow.get(index); - - int renderRequestFlags = 0; - - Texture content = checkTexture(entry.content); - if (content == null) { - content = mWaitLoadingTexture; - entry.isWaitDisplayed = true; - } else if (entry.isWaitDisplayed) { - entry.isWaitDisplayed = false; - content = new FadeInTexture(mPlaceholderColor, entry.bitmapTexture); - entry.content = content; - } - drawContent(canvas, content, width, height, entry.rotation); - if ((content instanceof FadeInTexture) && - ((FadeInTexture) content).isAnimating()) { - renderRequestFlags |= SlotView.RENDER_MORE_FRAME; - } - - if (entry.mediaType == MediaObject.MEDIA_TYPE_VIDEO) { - drawVideoOverlay(canvas, width, height); - } - - if (entry.isPanorama) { - drawPanoramaIcon(canvas, width, height); - } - - renderRequestFlags |= renderOverlay(canvas, index, entry, width, height); - - return renderRequestFlags; - } - - private int renderOverlay(GLCanvas canvas, int index, - AlbumSlidingWindow.AlbumEntry entry, int width, int height) { - int renderRequestFlags = 0; - if (mPressedIndex == index) { - if (mAnimatePressedUp) { - drawPressedUpFrame(canvas, width, height); - renderRequestFlags |= SlotView.RENDER_MORE_FRAME; - if (isPressedUpFrameFinished()) { - mAnimatePressedUp = false; - mPressedIndex = -1; - } - } else { - drawPressedFrame(canvas, width, height); - } - } else if ((entry.path != null) && (mHighlightItemPath == entry.path)) { - drawSelectedFrame(canvas, width, height); - } else if (mInSelectionMode && mSelectionManager.isItemSelected(entry.path)) { - drawSelectedFrame(canvas, width, height); - } - return renderRequestFlags; - } - - private class MyDataModelListener implements AlbumSlidingWindow.Listener { - @Override - public void onContentChanged() { - mSlotView.invalidate(); - } - - @Override - public void onSizeChanged(int size) { - mSlotView.setSlotCount(size); - } - } - - public void resume() { - mDataWindow.resume(); - } - - public void pause() { - mDataWindow.pause(); - } - - @Override - public void prepareDrawing() { - mInSelectionMode = mSelectionManager.inSelectionMode(); - } - - @Override - public void onVisibleRangeChanged(int visibleStart, int visibleEnd) { - if (mDataWindow != null) { - mDataWindow.setActiveWindow(visibleStart, visibleEnd); - } - } - - @Override - public void onSlotSizeChanged(int width, int height) { - // Do nothing - } - - public void setSlotFilter(SlotFilter slotFilter) { - mSlotFilter = slotFilter; - } -} diff --git a/src/com/android/gallery3d/ui/AnimationTime.java b/src/com/android/gallery3d/ui/AnimationTime.java deleted file mode 100644 index 063677423..000000000 --- a/src/com/android/gallery3d/ui/AnimationTime.java +++ /dev/null @@ -1,45 +0,0 @@ - -/* - * Copyright (C) 2012 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.ui; - -import android.os.SystemClock; - -// -// The animation time should ideally be the vsync time the frame will be -// displayed, but that is an unknown time in the future. So we use the system -// time just after eglSwapBuffers (when GLSurfaceView.onDrawFrame is called) -// as a approximation. -// -public class AnimationTime { - private static volatile long sTime; - - // Sets current time as the animation time. - public static void update() { - sTime = SystemClock.uptimeMillis(); - } - - // Returns the animation time. - public static long get() { - return sTime; - } - - public static long startTime() { - sTime = SystemClock.uptimeMillis(); - return sTime; - } -} diff --git a/src/com/android/gallery3d/ui/BitmapLoader.java b/src/com/android/gallery3d/ui/BitmapLoader.java deleted file mode 100644 index a708a90f3..000000000 --- a/src/com/android/gallery3d/ui/BitmapLoader.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * 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.ui; - -import android.graphics.Bitmap; - -import com.android.photos.data.GalleryBitmapPool; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.FutureListener; - -// We use this class to -// 1.) load bitmaps in background. -// 2.) as a place holder for the loaded bitmap -public abstract class BitmapLoader implements FutureListener<Bitmap> { - @SuppressWarnings("unused") - private static final String TAG = "BitmapLoader"; - - /* Transition Map: - * INIT -> REQUESTED, RECYCLED - * REQUESTED -> INIT (cancel), LOADED, ERROR, RECYCLED - * LOADED, ERROR -> RECYCLED - */ - private static final int STATE_INIT = 0; - private static final int STATE_REQUESTED = 1; - private static final int STATE_LOADED = 2; - private static final int STATE_ERROR = 3; - private static final int STATE_RECYCLED = 4; - - private int mState = STATE_INIT; - // mTask is not null only when a task is on the way - private Future<Bitmap> mTask; - private Bitmap mBitmap; - - @Override - public void onFutureDone(Future<Bitmap> future) { - synchronized (this) { - mTask = null; - mBitmap = future.get(); - if (mState == STATE_RECYCLED) { - if (mBitmap != null) { - GalleryBitmapPool.getInstance().put(mBitmap); - mBitmap = null; - } - return; // don't call callback - } - if (future.isCancelled() && mBitmap == null) { - if (mState == STATE_REQUESTED) mTask = submitBitmapTask(this); - return; // don't call callback - } else { - mState = mBitmap == null ? STATE_ERROR : STATE_LOADED; - } - } - onLoadComplete(mBitmap); - } - - public synchronized void startLoad() { - if (mState == STATE_INIT) { - mState = STATE_REQUESTED; - if (mTask == null) mTask = submitBitmapTask(this); - } - } - - public synchronized void cancelLoad() { - if (mState == STATE_REQUESTED) { - mState = STATE_INIT; - if (mTask != null) mTask.cancel(); - } - } - - // Recycle the loader and the bitmap - public synchronized void recycle() { - mState = STATE_RECYCLED; - if (mBitmap != null) { - GalleryBitmapPool.getInstance().put(mBitmap); - mBitmap = null; - } - if (mTask != null) mTask.cancel(); - } - - public synchronized boolean isRequestInProgress() { - return mState == STATE_REQUESTED; - } - - public synchronized boolean isRecycled() { - return mState == STATE_RECYCLED; - } - - public synchronized Bitmap getBitmap() { - return mBitmap; - } - - abstract protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l); - abstract protected void onLoadComplete(Bitmap bitmap); -} diff --git a/src/com/android/gallery3d/ui/BitmapScreenNail.java b/src/com/android/gallery3d/ui/BitmapScreenNail.java deleted file mode 100644 index a3d403946..000000000 --- a/src/com/android/gallery3d/ui/BitmapScreenNail.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.graphics.Bitmap; -import android.graphics.RectF; - -import com.android.gallery3d.glrenderer.BitmapTexture; -import com.android.gallery3d.glrenderer.GLCanvas; - -public class BitmapScreenNail implements ScreenNail { - private final BitmapTexture mBitmapTexture; - - public BitmapScreenNail(Bitmap bitmap) { - mBitmapTexture = new BitmapTexture(bitmap); - } - - @Override - public int getWidth() { - return mBitmapTexture.getWidth(); - } - - @Override - public int getHeight() { - return mBitmapTexture.getHeight(); - } - - @Override - public void draw(GLCanvas canvas, int x, int y, int width, int height) { - mBitmapTexture.draw(canvas, x, y, width, height); - } - - @Override - public void noDraw() { - // do nothing - } - - @Override - public void recycle() { - mBitmapTexture.recycle(); - } - - @Override - public void draw(GLCanvas canvas, RectF source, RectF dest) { - canvas.drawTexture(mBitmapTexture, source, dest); - } -} diff --git a/src/com/android/gallery3d/ui/BitmapTileProvider.java b/src/com/android/gallery3d/ui/BitmapTileProvider.java deleted file mode 100644 index e1a8b7644..000000000 --- a/src/com/android/gallery3d/ui/BitmapTileProvider.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * 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.ui; - -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.Canvas; - -import com.android.gallery3d.common.BitmapUtils; -import com.android.photos.data.GalleryBitmapPool; - -import java.util.ArrayList; - -public class BitmapTileProvider implements TileImageView.TileSource { - private final ScreenNail mScreenNail; - private final Bitmap[] mMipmaps; - private final Config mConfig; - private final int mImageWidth; - private final int mImageHeight; - - private boolean mRecycled = false; - - public BitmapTileProvider(Bitmap bitmap, int maxBackupSize) { - mImageWidth = bitmap.getWidth(); - mImageHeight = bitmap.getHeight(); - ArrayList<Bitmap> list = new ArrayList<Bitmap>(); - list.add(bitmap); - while (bitmap.getWidth() > maxBackupSize - || bitmap.getHeight() > maxBackupSize) { - bitmap = BitmapUtils.resizeBitmapByScale(bitmap, 0.5f, false); - list.add(bitmap); - } - - mScreenNail = new BitmapScreenNail(list.remove(list.size() - 1)); - mMipmaps = list.toArray(new Bitmap[list.size()]); - mConfig = Config.ARGB_8888; - } - - @Override - public ScreenNail getScreenNail() { - return mScreenNail; - } - - @Override - public int getImageHeight() { - return mImageHeight; - } - - @Override - public int getImageWidth() { - return mImageWidth; - } - - @Override - public int getLevelCount() { - return mMipmaps.length; - } - - @Override - public Bitmap getTile(int level, int x, int y, int tileSize) { - x >>= level; - y >>= level; - - Bitmap result = GalleryBitmapPool.getInstance().get(tileSize, tileSize); - if (result == null) { - result = Bitmap.createBitmap(tileSize, tileSize, mConfig); - } else { - result.eraseColor(0); - } - - Bitmap mipmap = mMipmaps[level]; - Canvas canvas = new Canvas(result); - int offsetX = -x; - int offsetY = -y; - canvas.drawBitmap(mipmap, offsetX, offsetY, null); - return result; - } - - public void recycle() { - if (mRecycled) return; - mRecycled = true; - for (Bitmap bitmap : mMipmaps) { - BitmapUtils.recycleSilently(bitmap); - } - if (mScreenNail != null) { - mScreenNail.recycle(); - } - } -} diff --git a/src/com/android/gallery3d/ui/CacheStorageUsageInfo.java b/src/com/android/gallery3d/ui/CacheStorageUsageInfo.java deleted file mode 100644 index 46f7a2433..000000000 --- a/src/com/android/gallery3d/ui/CacheStorageUsageInfo.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.os.StatFs; - -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.util.ThreadPool.JobContext; - -import java.io.File; - -public class CacheStorageUsageInfo { - @SuppressWarnings("unused") - private static final String TAG = "CacheStorageUsageInfo"; - - // number of bytes the storage has. - private long mTotalBytes; - - // number of bytes already used. - private long mUsedBytes; - - // number of bytes used for the cache (should be less then usedBytes). - private long mUsedCacheBytes; - - // number of bytes used for the cache if all pending downloads (and removals) are completed. - private long mTargetCacheBytes; - - private AbstractGalleryActivity mActivity; - private Context mContext; - private long mUserChangeDelta; - - public CacheStorageUsageInfo(AbstractGalleryActivity activity) { - mActivity = activity; - mContext = activity.getAndroidContext(); - } - - public void increaseTargetCacheSize(long delta) { - mUserChangeDelta += delta; - } - - public void loadStorageInfo(JobContext jc) { - File cacheDir = mContext.getExternalCacheDir(); - if (cacheDir == null) { - cacheDir = mContext.getCacheDir(); - } - - String path = cacheDir.getAbsolutePath(); - StatFs stat = new StatFs(path); - long blockSize = stat.getBlockSize(); - long availableBlocks = stat.getAvailableBlocks(); - long totalBlocks = stat.getBlockCount(); - - mTotalBytes = blockSize * totalBlocks; - mUsedBytes = blockSize * (totalBlocks - availableBlocks); - mUsedCacheBytes = mActivity.getDataManager().getTotalUsedCacheSize(); - mTargetCacheBytes = mActivity.getDataManager().getTotalTargetCacheSize(); - } - - public long getTotalBytes() { - return mTotalBytes; - } - - public long getExpectedUsedBytes() { - return mUsedBytes - mUsedCacheBytes + mTargetCacheBytes + mUserChangeDelta; - } - - public long getUsedBytes() { - // Should it be usedBytes - usedCacheBytes + targetCacheBytes ? - return mUsedBytes; - } - - public long getFreeBytes() { - return mTotalBytes - mUsedBytes; - } -} diff --git a/src/com/android/gallery3d/ui/CaptureAnimation.java b/src/com/android/gallery3d/ui/CaptureAnimation.java deleted file mode 100644 index 87c054ab3..000000000 --- a/src/com/android/gallery3d/ui/CaptureAnimation.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.view.animation.AccelerateDecelerateInterpolator; -import android.view.animation.AccelerateInterpolator; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; - -public class CaptureAnimation { - // The amount of change for zooming out. - private static final float ZOOM_DELTA = 0.2f; - // Pre-calculated value for convenience. - private static final float ZOOM_IN_BEGIN = 1f - ZOOM_DELTA; - - private static final Interpolator sZoomOutInterpolator = - new DecelerateInterpolator(); - private static final Interpolator sZoomInInterpolator = - new AccelerateInterpolator(); - private static final Interpolator sSlideInterpolator = - new AccelerateDecelerateInterpolator(); - - // Calculate the slide factor based on the give time fraction. - public static float calculateSlide(float fraction) { - return sSlideInterpolator.getInterpolation(fraction); - } - - // Calculate the scale factor based on the given time fraction. - public static float calculateScale(float fraction) { - float value; - if (fraction <= 0.5f) { - // Zoom in for the beginning. - value = 1f - ZOOM_DELTA * - sZoomOutInterpolator.getInterpolation(fraction * 2); - } else { - // Zoom out for the ending. - value = ZOOM_IN_BEGIN + ZOOM_DELTA * - sZoomInInterpolator.getInterpolation((fraction - 0.5f) * 2f); - } - return value; - } -} diff --git a/src/com/android/gallery3d/ui/DetailsAddressResolver.java b/src/com/android/gallery3d/ui/DetailsAddressResolver.java deleted file mode 100644 index 8de667745..000000000 --- a/src/com/android/gallery3d/ui/DetailsAddressResolver.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * Copyright (C) 2011 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.ui; - -import android.content.Context; -import android.location.Address; -import android.os.Handler; -import android.os.Looper; - -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.data.MediaDetails; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.FutureListener; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.ReverseGeocoder; -import com.android.gallery3d.util.ThreadPool.Job; -import com.android.gallery3d.util.ThreadPool.JobContext; - -public class DetailsAddressResolver { - private AddressResolvingListener mListener; - private final AbstractGalleryActivity mContext; - private Future<Address> mAddressLookupJob; - private final Handler mHandler; - - private class AddressLookupJob implements Job<Address> { - private double[] mLatlng; - - protected AddressLookupJob(double[] latlng) { - mLatlng = latlng; - } - - @Override - public Address run(JobContext jc) { - ReverseGeocoder geocoder = new ReverseGeocoder(mContext.getAndroidContext()); - return geocoder.lookupAddress(mLatlng[0], mLatlng[1], true); - } - } - - public interface AddressResolvingListener { - public void onAddressAvailable(String address); - } - - public DetailsAddressResolver(AbstractGalleryActivity context) { - mContext = context; - mHandler = new Handler(Looper.getMainLooper()); - } - - public String resolveAddress(double[] latlng, AddressResolvingListener listener) { - mListener = listener; - mAddressLookupJob = mContext.getThreadPool().submit( - new AddressLookupJob(latlng), - new FutureListener<Address>() { - @Override - public void onFutureDone(final Future<Address> future) { - mAddressLookupJob = null; - if (!future.isCancelled()) { - mHandler.post(new Runnable() { - @Override - public void run() { - updateLocation(future.get()); - } - }); - } - } - }); - return GalleryUtils.formatLatitudeLongitude("(%f,%f)", latlng[0], latlng[1]); - } - - private void updateLocation(Address address) { - if (address != null) { - Context context = mContext.getAndroidContext(); - String parts[] = { - address.getAdminArea(), - address.getSubAdminArea(), - address.getLocality(), - address.getSubLocality(), - address.getThoroughfare(), - address.getSubThoroughfare(), - address.getPremises(), - address.getPostalCode(), - address.getCountryName() - }; - - String addressText = ""; - for (int i = 0; i < parts.length; i++) { - if (parts[i] == null || parts[i].isEmpty()) continue; - if (!addressText.isEmpty()) { - addressText += ", "; - } - addressText += parts[i]; - } - String text = String.format("%s : %s", DetailsHelper.getDetailsName( - context, MediaDetails.INDEX_LOCATION), addressText); - mListener.onAddressAvailable(text); - } - } - - public void cancel() { - if (mAddressLookupJob != null) { - mAddressLookupJob.cancel(); - mAddressLookupJob = null; - } - } -} diff --git a/src/com/android/gallery3d/ui/DetailsHelper.java b/src/com/android/gallery3d/ui/DetailsHelper.java deleted file mode 100644 index 47296f655..000000000 --- a/src/com/android/gallery3d/ui/DetailsHelper.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.view.View.MeasureSpec; - -import com.android.gallery3d.R; -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.data.MediaDetails; -import com.android.gallery3d.ui.DetailsAddressResolver.AddressResolvingListener; - -public class DetailsHelper { - private static DetailsAddressResolver sAddressResolver; - private DetailsViewContainer mContainer; - - public interface DetailsSource { - public int size(); - public int setIndex(); - public MediaDetails getDetails(); - } - - public interface CloseListener { - public void onClose(); - } - - public interface DetailsViewContainer { - public void reloadDetails(); - public void setCloseListener(CloseListener listener); - public void show(); - public void hide(); - } - - public interface ResolutionResolvingListener { - public void onResolutionAvailable(int width, int height); - } - - public DetailsHelper(AbstractGalleryActivity activity, GLView rootPane, DetailsSource source) { - mContainer = new DialogDetailsView(activity, source); - } - - public void layout(int left, int top, int right, int bottom) { - if (mContainer instanceof GLView) { - GLView view = (GLView) mContainer; - view.measure(MeasureSpec.UNSPECIFIED, - MeasureSpec.makeMeasureSpec(bottom - top, MeasureSpec.AT_MOST)); - view.layout(0, top, view.getMeasuredWidth(), top + view.getMeasuredHeight()); - } - } - - public void reloadDetails() { - mContainer.reloadDetails(); - } - - public void setCloseListener(CloseListener listener) { - mContainer.setCloseListener(listener); - } - - public static String resolveAddress(AbstractGalleryActivity activity, double[] latlng, - AddressResolvingListener listener) { - if (sAddressResolver == null) { - sAddressResolver = new DetailsAddressResolver(activity); - } else { - sAddressResolver.cancel(); - } - return sAddressResolver.resolveAddress(latlng, listener); - } - - public static void resolveResolution(String path, ResolutionResolvingListener listener) { - Bitmap bitmap = BitmapFactory.decodeFile(path); - if (bitmap == null) return; - listener.onResolutionAvailable(bitmap.getWidth(), bitmap.getHeight()); - } - - public static void pause() { - if (sAddressResolver != null) sAddressResolver.cancel(); - } - - public void show() { - mContainer.show(); - } - - public void hide() { - mContainer.hide(); - } - - public static String getDetailsName(Context context, int key) { - switch (key) { - case MediaDetails.INDEX_TITLE: - return context.getString(R.string.title); - case MediaDetails.INDEX_DESCRIPTION: - return context.getString(R.string.description); - case MediaDetails.INDEX_DATETIME: - return context.getString(R.string.time); - case MediaDetails.INDEX_LOCATION: - return context.getString(R.string.location); - case MediaDetails.INDEX_PATH: - return context.getString(R.string.path); - case MediaDetails.INDEX_WIDTH: - return context.getString(R.string.width); - case MediaDetails.INDEX_HEIGHT: - return context.getString(R.string.height); - case MediaDetails.INDEX_ORIENTATION: - return context.getString(R.string.orientation); - case MediaDetails.INDEX_DURATION: - return context.getString(R.string.duration); - case MediaDetails.INDEX_MIMETYPE: - return context.getString(R.string.mimetype); - case MediaDetails.INDEX_SIZE: - return context.getString(R.string.file_size); - case MediaDetails.INDEX_MAKE: - return context.getString(R.string.maker); - case MediaDetails.INDEX_MODEL: - return context.getString(R.string.model); - case MediaDetails.INDEX_FLASH: - return context.getString(R.string.flash); - case MediaDetails.INDEX_APERTURE: - return context.getString(R.string.aperture); - case MediaDetails.INDEX_FOCAL_LENGTH: - return context.getString(R.string.focal_length); - case MediaDetails.INDEX_WHITE_BALANCE: - return context.getString(R.string.white_balance); - case MediaDetails.INDEX_EXPOSURE_TIME: - return context.getString(R.string.exposure_time); - case MediaDetails.INDEX_ISO: - return context.getString(R.string.iso); - default: - return "Unknown key" + key; - } - } -} - - diff --git a/src/com/android/gallery3d/ui/DialogDetailsView.java b/src/com/android/gallery3d/ui/DialogDetailsView.java deleted file mode 100644 index 058c03654..000000000 --- a/src/com/android/gallery3d/ui/DialogDetailsView.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright (C) 2011 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.ui; - -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnDismissListener; -import android.text.format.Formatter; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.BaseAdapter; -import android.widget.ListView; -import android.widget.TextView; - -import com.android.gallery3d.R; -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.MediaDetails; -import com.android.gallery3d.ui.DetailsAddressResolver.AddressResolvingListener; -import com.android.gallery3d.ui.DetailsHelper.CloseListener; -import com.android.gallery3d.ui.DetailsHelper.DetailsSource; -import com.android.gallery3d.ui.DetailsHelper.DetailsViewContainer; -import com.android.gallery3d.ui.DetailsHelper.ResolutionResolvingListener; - -import java.util.ArrayList; -import java.util.Map.Entry; - -public class DialogDetailsView implements DetailsViewContainer { - @SuppressWarnings("unused") - private static final String TAG = "DialogDetailsView"; - - private final AbstractGalleryActivity mActivity; - private DetailsAdapter mAdapter; - private MediaDetails mDetails; - private final DetailsSource mSource; - private int mIndex; - private Dialog mDialog; - private CloseListener mListener; - - public DialogDetailsView(AbstractGalleryActivity activity, DetailsSource source) { - mActivity = activity; - mSource = source; - } - - @Override - public void show() { - reloadDetails(); - mDialog.show(); - } - - @Override - public void hide() { - mDialog.hide(); - } - - @Override - public void reloadDetails() { - int index = mSource.setIndex(); - if (index == -1) return; - MediaDetails details = mSource.getDetails(); - if (details != null) { - if (mIndex == index && mDetails == details) return; - mIndex = index; - mDetails = details; - setDetails(details); - } - } - - private void setDetails(MediaDetails details) { - mAdapter = new DetailsAdapter(details); - String title = String.format( - mActivity.getAndroidContext().getString(R.string.details_title), - mIndex + 1, mSource.size()); - ListView detailsList = (ListView) LayoutInflater.from(mActivity.getAndroidContext()).inflate( - R.layout.details_list, null, false); - detailsList.setAdapter(mAdapter); - mDialog = new AlertDialog.Builder(mActivity) - .setView(detailsList) - .setTitle(title) - .setPositiveButton(R.string.close, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int whichButton) { - mDialog.dismiss(); - } - }) - .create(); - - mDialog.setOnDismissListener(new OnDismissListener() { - @Override - public void onDismiss(DialogInterface dialog) { - if (mListener != null) { - mListener.onClose(); - } - } - }); - } - - - private class DetailsAdapter extends BaseAdapter - implements AddressResolvingListener, ResolutionResolvingListener { - private final ArrayList<String> mItems; - private int mLocationIndex; - private int mWidthIndex = -1; - private int mHeightIndex = -1; - - public DetailsAdapter(MediaDetails details) { - Context context = mActivity.getAndroidContext(); - mItems = new ArrayList<String>(details.size()); - mLocationIndex = -1; - setDetails(context, details); - } - - private void setDetails(Context context, MediaDetails details) { - boolean resolutionIsValid = true; - String path = null; - for (Entry<Integer, Object> detail : details) { - String value; - switch (detail.getKey()) { - case MediaDetails.INDEX_LOCATION: { - double[] latlng = (double[]) detail.getValue(); - mLocationIndex = mItems.size(); - value = DetailsHelper.resolveAddress(mActivity, latlng, this); - break; - } - case MediaDetails.INDEX_SIZE: { - value = Formatter.formatFileSize( - context, (Long) detail.getValue()); - break; - } - case MediaDetails.INDEX_WHITE_BALANCE: { - value = "1".equals(detail.getValue()) - ? context.getString(R.string.manual) - : context.getString(R.string.auto); - break; - } - case MediaDetails.INDEX_FLASH: { - MediaDetails.FlashState flash = - (MediaDetails.FlashState) detail.getValue(); - // TODO: camera doesn't fill in the complete values, show more information - // when it is fixed. - if (flash.isFlashFired()) { - value = context.getString(R.string.flash_on); - } else { - value = context.getString(R.string.flash_off); - } - break; - } - case MediaDetails.INDEX_EXPOSURE_TIME: { - value = (String) detail.getValue(); - double time = Double.valueOf(value); - if (time < 1.0f) { - value = String.format("1/%d", (int) (0.5f + 1 / time)); - } else { - int integer = (int) time; - time -= integer; - value = String.valueOf(integer) + "''"; - if (time > 0.0001) { - value += String.format(" 1/%d", (int) (0.5f + 1 / time)); - } - } - break; - } - case MediaDetails.INDEX_WIDTH: - mWidthIndex = mItems.size(); - value = detail.getValue().toString(); - if (value.equalsIgnoreCase("0")) { - value = context.getString(R.string.unknown); - resolutionIsValid = false; - } - break; - case MediaDetails.INDEX_HEIGHT: { - mHeightIndex = mItems.size(); - value = detail.getValue().toString(); - if (value.equalsIgnoreCase("0")) { - value = context.getString(R.string.unknown); - resolutionIsValid = false; - } - break; - } - case MediaDetails.INDEX_PATH: - // Get the path and then fall through to the default case - path = detail.getValue().toString(); - default: { - Object valueObj = detail.getValue(); - // This shouldn't happen, log its key to help us diagnose the problem. - if (valueObj == null) { - Utils.fail("%s's value is Null", - DetailsHelper.getDetailsName(context, detail.getKey())); - } - value = valueObj.toString(); - } - } - int key = detail.getKey(); - if (details.hasUnit(key)) { - value = String.format("%s: %s %s", DetailsHelper.getDetailsName( - context, key), value, context.getString(details.getUnit(key))); - } else { - value = String.format("%s: %s", DetailsHelper.getDetailsName( - context, key), value); - } - mItems.add(value); - if (!resolutionIsValid) { - DetailsHelper.resolveResolution(path, this); - } - } - } - - @Override - public boolean areAllItemsEnabled() { - return false; - } - - @Override - public boolean isEnabled(int position) { - return false; - } - - @Override - public int getCount() { - return mItems.size(); - } - - @Override - public Object getItem(int position) { - return mDetails.getDetail(position); - } - - @Override - public long getItemId(int position) { - return position; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - TextView tv; - if (convertView == null) { - tv = (TextView) LayoutInflater.from(mActivity.getAndroidContext()).inflate( - R.layout.details, parent, false); - } else { - tv = (TextView) convertView; - } - tv.setText(mItems.get(position)); - return tv; - } - - @Override - public void onAddressAvailable(String address) { - mItems.set(mLocationIndex, address); - notifyDataSetChanged(); - } - - @Override - public void onResolutionAvailable(int width, int height) { - if (width == 0 || height == 0) return; - // Update the resolution with the new width and height - Context context = mActivity.getAndroidContext(); - String widthString = String.format("%s: %d", DetailsHelper.getDetailsName( - context, MediaDetails.INDEX_WIDTH), width); - String heightString = String.format("%s: %d", DetailsHelper.getDetailsName( - context, MediaDetails.INDEX_HEIGHT), height); - mItems.set(mWidthIndex, String.valueOf(widthString)); - mItems.set(mHeightIndex, String.valueOf(heightString)); - notifyDataSetChanged(); - } - } - - @Override - public void setCloseListener(CloseListener listener) { - mListener = listener; - } -} diff --git a/src/com/android/gallery3d/ui/DownUpDetector.java b/src/com/android/gallery3d/ui/DownUpDetector.java deleted file mode 100644 index 19db77262..000000000 --- a/src/com/android/gallery3d/ui/DownUpDetector.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.ui; - -import android.view.MotionEvent; - -public class DownUpDetector { - public interface DownUpListener { - void onDown(MotionEvent e); - void onUp(MotionEvent e); - } - - private boolean mStillDown; - private DownUpListener mListener; - - public DownUpDetector(DownUpListener listener) { - mListener = listener; - } - - private void setState(boolean down, MotionEvent e) { - if (down == mStillDown) return; - mStillDown = down; - if (down) { - mListener.onDown(e); - } else { - mListener.onUp(e); - } - } - - public void onTouchEvent(MotionEvent ev) { - switch (ev.getAction() & MotionEvent.ACTION_MASK) { - case MotionEvent.ACTION_DOWN: - setState(true, ev); - break; - - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - case MotionEvent.ACTION_POINTER_DOWN: // Multitouch event - abort. - setState(false, ev); - break; - } - } - - public boolean isDown() { - return mStillDown; - } -} diff --git a/src/com/android/gallery3d/ui/EdgeEffect.java b/src/com/android/gallery3d/ui/EdgeEffect.java deleted file mode 100644 index 87ff0c5d3..000000000 --- a/src/com/android/gallery3d/ui/EdgeEffect.java +++ /dev/null @@ -1,443 +0,0 @@ -/* - * Copyright (C) 2011 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.ui; - -import android.content.Context; -import android.graphics.Canvas; -import android.graphics.Rect; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; - -import com.android.gallery3d.R; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.ResourceTexture; - -// This is copied from android.widget.EdgeEffect with some small modifications: -// (1) Copy the images (overscroll_{edge|glow}.png) to local resources. -// (2) Use "GLCanvas" instead of "Canvas" for draw()'s parameter. -// (3) Use a private Drawable class (which inherits from ResourceTexture) -// instead of android.graphics.drawable.Drawable to hold the images. -// The private Drawable class is used to translate original Canvas calls to -// corresponding GLCanvas calls. - -/** - * This class performs the graphical effect used at the edges of scrollable widgets - * when the user scrolls beyond the content bounds in 2D space. - * - * <p>EdgeEffect is stateful. Custom widgets using EdgeEffect should create an - * instance for each edge that should show the effect, feed it input data using - * the methods {@link #onAbsorb(int)}, {@link #onPull(float)}, and {@link #onRelease()}, - * and draw the effect using {@link #draw(Canvas)} in the widget's overridden - * {@link android.view.View#draw(Canvas)} method. If {@link #isFinished()} returns - * false after drawing, the edge effect's animation is not yet complete and the widget - * should schedule another drawing pass to continue the animation.</p> - * - * <p>When drawing, widgets should draw their main content and child views first, - * usually by invoking <code>super.draw(canvas)</code> from an overridden <code>draw</code> - * method. (This will invoke onDraw and dispatch drawing to child views as needed.) - * The edge effect may then be drawn on top of the view's content using the - * {@link #draw(Canvas)} method.</p> - */ -public class EdgeEffect { - @SuppressWarnings("unused") - private static final String TAG = "EdgeEffect"; - - // Time it will take the effect to fully recede in ms - private static final int RECEDE_TIME = 1000; - - // Time it will take before a pulled glow begins receding in ms - private static final int PULL_TIME = 167; - - // Time it will take in ms for a pulled glow to decay to partial strength before release - private static final int PULL_DECAY_TIME = 1000; - - private static final float MAX_ALPHA = 0.8f; - private static final float HELD_EDGE_ALPHA = 0.7f; - private static final float HELD_EDGE_SCALE_Y = 0.5f; - private static final float HELD_GLOW_ALPHA = 0.5f; - private static final float HELD_GLOW_SCALE_Y = 0.5f; - - private static final float MAX_GLOW_HEIGHT = 4.f; - - private static final float PULL_GLOW_BEGIN = 1.f; - private static final float PULL_EDGE_BEGIN = 0.6f; - - // Minimum velocity that will be absorbed - private static final int MIN_VELOCITY = 100; - - private static final float EPSILON = 0.001f; - - private final Drawable mEdge; - private final Drawable mGlow; - private int mWidth; - private int mHeight; - private final int MIN_WIDTH = 300; - private final int mMinWidth; - - private float mEdgeAlpha; - private float mEdgeScaleY; - private float mGlowAlpha; - private float mGlowScaleY; - - private float mEdgeAlphaStart; - private float mEdgeAlphaFinish; - private float mEdgeScaleYStart; - private float mEdgeScaleYFinish; - private float mGlowAlphaStart; - private float mGlowAlphaFinish; - private float mGlowScaleYStart; - private float mGlowScaleYFinish; - - private long mStartTime; - private float mDuration; - - private final Interpolator mInterpolator; - - private static final int STATE_IDLE = 0; - private static final int STATE_PULL = 1; - private static final int STATE_ABSORB = 2; - private static final int STATE_RECEDE = 3; - private static final int STATE_PULL_DECAY = 4; - - // How much dragging should effect the height of the edge image. - // Number determined by user testing. - private static final int PULL_DISTANCE_EDGE_FACTOR = 7; - - // How much dragging should effect the height of the glow image. - // Number determined by user testing. - private static final int PULL_DISTANCE_GLOW_FACTOR = 7; - private static final float PULL_DISTANCE_ALPHA_GLOW_FACTOR = 1.1f; - - private static final int VELOCITY_EDGE_FACTOR = 8; - private static final int VELOCITY_GLOW_FACTOR = 16; - - private int mState = STATE_IDLE; - - private float mPullDistance; - - /** - * Construct a new EdgeEffect with a theme appropriate for the provided context. - * @param context Context used to provide theming and resource information for the EdgeEffect - */ - public EdgeEffect(Context context) { - mEdge = new Drawable(context, R.drawable.overscroll_edge); - mGlow = new Drawable(context, R.drawable.overscroll_glow); - - mMinWidth = (int) (context.getResources().getDisplayMetrics().density * MIN_WIDTH + 0.5f); - mInterpolator = new DecelerateInterpolator(); - } - - /** - * Set the size of this edge effect in pixels. - * - * @param width Effect width in pixels - * @param height Effect height in pixels - */ - public void setSize(int width, int height) { - mWidth = width; - mHeight = height; - } - - /** - * Reports if this EdgeEffect's animation is finished. If this method returns false - * after a call to {@link #draw(Canvas)} the host widget should schedule another - * drawing pass to continue the animation. - * - * @return true if animation is finished, false if drawing should continue on the next frame. - */ - public boolean isFinished() { - return mState == STATE_IDLE; - } - - /** - * Immediately finish the current animation. - * After this call {@link #isFinished()} will return true. - */ - public void finish() { - mState = STATE_IDLE; - } - - /** - * A view should call this when content is pulled away from an edge by the user. - * This will update the state of the current visual effect and its associated animation. - * The host view should always {@link android.view.View#invalidate()} after this - * and draw the results accordingly. - * - * @param deltaDistance Change in distance since the last call. Values may be 0 (no change) to - * 1.f (full length of the view) or negative values to express change - * back toward the edge reached to initiate the effect. - */ - public void onPull(float deltaDistance) { - final long now = AnimationTime.get(); - if (mState == STATE_PULL_DECAY && now - mStartTime < mDuration) { - return; - } - if (mState != STATE_PULL) { - mGlowScaleY = PULL_GLOW_BEGIN; - } - mState = STATE_PULL; - - mStartTime = now; - mDuration = PULL_TIME; - - mPullDistance += deltaDistance; - float distance = Math.abs(mPullDistance); - - mEdgeAlpha = mEdgeAlphaStart = Math.max(PULL_EDGE_BEGIN, Math.min(distance, MAX_ALPHA)); - mEdgeScaleY = mEdgeScaleYStart = Math.max( - HELD_EDGE_SCALE_Y, Math.min(distance * PULL_DISTANCE_EDGE_FACTOR, 1.f)); - - mGlowAlpha = mGlowAlphaStart = Math.min(MAX_ALPHA, - mGlowAlpha + - (Math.abs(deltaDistance) * PULL_DISTANCE_ALPHA_GLOW_FACTOR)); - - float glowChange = Math.abs(deltaDistance); - if (deltaDistance > 0 && mPullDistance < 0) { - glowChange = -glowChange; - } - if (mPullDistance == 0) { - mGlowScaleY = 0; - } - - // Do not allow glow to get larger than MAX_GLOW_HEIGHT. - mGlowScaleY = mGlowScaleYStart = Math.min(MAX_GLOW_HEIGHT, Math.max( - 0, mGlowScaleY + glowChange * PULL_DISTANCE_GLOW_FACTOR)); - - mEdgeAlphaFinish = mEdgeAlpha; - mEdgeScaleYFinish = mEdgeScaleY; - mGlowAlphaFinish = mGlowAlpha; - mGlowScaleYFinish = mGlowScaleY; - } - - /** - * Call when the object is released after being pulled. - * This will begin the "decay" phase of the effect. After calling this method - * the host view should {@link android.view.View#invalidate()} and thereby - * draw the results accordingly. - */ - public void onRelease() { - mPullDistance = 0; - - if (mState != STATE_PULL && mState != STATE_PULL_DECAY) { - return; - } - - mState = STATE_RECEDE; - mEdgeAlphaStart = mEdgeAlpha; - mEdgeScaleYStart = mEdgeScaleY; - mGlowAlphaStart = mGlowAlpha; - mGlowScaleYStart = mGlowScaleY; - - mEdgeAlphaFinish = 0.f; - mEdgeScaleYFinish = 0.f; - mGlowAlphaFinish = 0.f; - mGlowScaleYFinish = 0.f; - - mStartTime = AnimationTime.get(); - mDuration = RECEDE_TIME; - } - - /** - * Call when the effect absorbs an impact at the given velocity. - * Used when a fling reaches the scroll boundary. - * - * <p>When using a {@link android.widget.Scroller} or {@link android.widget.OverScroller}, - * the method <code>getCurrVelocity</code> will provide a reasonable approximation - * to use here.</p> - * - * @param velocity Velocity at impact in pixels per second. - */ - public void onAbsorb(int velocity) { - mState = STATE_ABSORB; - velocity = Math.max(MIN_VELOCITY, Math.abs(velocity)); - - mStartTime = AnimationTime.get(); - mDuration = 0.1f + (velocity * 0.03f); - - // The edge should always be at least partially visible, regardless - // of velocity. - mEdgeAlphaStart = 0.f; - mEdgeScaleY = mEdgeScaleYStart = 0.f; - // The glow depends more on the velocity, and therefore starts out - // nearly invisible. - mGlowAlphaStart = 0.5f; - mGlowScaleYStart = 0.f; - - // Factor the velocity by 8. Testing on device shows this works best to - // reflect the strength of the user's scrolling. - mEdgeAlphaFinish = Math.max(0, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1)); - // Edge should never get larger than the size of its asset. - mEdgeScaleYFinish = Math.max( - HELD_EDGE_SCALE_Y, Math.min(velocity * VELOCITY_EDGE_FACTOR, 1.f)); - - // Growth for the size of the glow should be quadratic to properly - // respond - // to a user's scrolling speed. The faster the scrolling speed, the more - // intense the effect should be for both the size and the saturation. - mGlowScaleYFinish = Math.min(0.025f + (velocity * (velocity / 100) * 0.00015f), 1.75f); - // Alpha should change for the glow as well as size. - mGlowAlphaFinish = Math.max( - mGlowAlphaStart, Math.min(velocity * VELOCITY_GLOW_FACTOR * .00001f, MAX_ALPHA)); - } - - - /** - * Draw into the provided canvas. Assumes that the canvas has been rotated - * accordingly and the size has been set. The effect will be drawn the full - * width of X=0 to X=width, beginning from Y=0 and extending to some factor < - * 1.f of height. - * - * @param canvas Canvas to draw into - * @return true if drawing should continue beyond this frame to continue the - * animation - */ - public boolean draw(GLCanvas canvas) { - update(); - - final int edgeHeight = mEdge.getIntrinsicHeight(); - final int edgeWidth = mEdge.getIntrinsicWidth(); - final int glowHeight = mGlow.getIntrinsicHeight(); - final int glowWidth = mGlow.getIntrinsicWidth(); - - mGlow.setAlpha((int) (Math.max(0, Math.min(mGlowAlpha, 1)) * 255)); - - int glowBottom = (int) Math.min( - glowHeight * mGlowScaleY * glowHeight/ glowWidth * 0.6f, - glowHeight * MAX_GLOW_HEIGHT); - if (mWidth < mMinWidth) { - // Center the glow and clip it. - int glowLeft = (mWidth - mMinWidth)/2; - mGlow.setBounds(glowLeft, 0, mWidth - glowLeft, glowBottom); - } else { - // Stretch the glow to fit. - mGlow.setBounds(0, 0, mWidth, glowBottom); - } - - mGlow.draw(canvas); - - mEdge.setAlpha((int) (Math.max(0, Math.min(mEdgeAlpha, 1)) * 255)); - - int edgeBottom = (int) (edgeHeight * mEdgeScaleY); - if (mWidth < mMinWidth) { - // Center the edge and clip it. - int edgeLeft = (mWidth - mMinWidth)/2; - mEdge.setBounds(edgeLeft, 0, mWidth - edgeLeft, edgeBottom); - } else { - // Stretch the edge to fit. - mEdge.setBounds(0, 0, mWidth, edgeBottom); - } - mEdge.draw(canvas); - - return mState != STATE_IDLE; - } - - private void update() { - final long time = AnimationTime.get(); - final float t = Math.min((time - mStartTime) / mDuration, 1.f); - - final float interp = mInterpolator.getInterpolation(t); - - mEdgeAlpha = mEdgeAlphaStart + (mEdgeAlphaFinish - mEdgeAlphaStart) * interp; - mEdgeScaleY = mEdgeScaleYStart + (mEdgeScaleYFinish - mEdgeScaleYStart) * interp; - mGlowAlpha = mGlowAlphaStart + (mGlowAlphaFinish - mGlowAlphaStart) * interp; - mGlowScaleY = mGlowScaleYStart + (mGlowScaleYFinish - mGlowScaleYStart) * interp; - - if (t >= 1.f - EPSILON) { - switch (mState) { - case STATE_ABSORB: - mState = STATE_RECEDE; - mStartTime = AnimationTime.get(); - mDuration = RECEDE_TIME; - - mEdgeAlphaStart = mEdgeAlpha; - mEdgeScaleYStart = mEdgeScaleY; - mGlowAlphaStart = mGlowAlpha; - mGlowScaleYStart = mGlowScaleY; - - // After absorb, the glow and edge should fade to nothing. - mEdgeAlphaFinish = 0.f; - mEdgeScaleYFinish = 0.f; - mGlowAlphaFinish = 0.f; - mGlowScaleYFinish = 0.f; - break; - case STATE_PULL: - mState = STATE_PULL_DECAY; - mStartTime = AnimationTime.get(); - mDuration = PULL_DECAY_TIME; - - mEdgeAlphaStart = mEdgeAlpha; - mEdgeScaleYStart = mEdgeScaleY; - mGlowAlphaStart = mGlowAlpha; - mGlowScaleYStart = mGlowScaleY; - - // After pull, the glow and edge should fade to nothing. - mEdgeAlphaFinish = 0.f; - mEdgeScaleYFinish = 0.f; - mGlowAlphaFinish = 0.f; - mGlowScaleYFinish = 0.f; - break; - case STATE_PULL_DECAY: - // When receding, we want edge to decrease more slowly - // than the glow. - float factor = mGlowScaleYFinish != 0 ? 1 - / (mGlowScaleYFinish * mGlowScaleYFinish) - : Float.MAX_VALUE; - mEdgeScaleY = mEdgeScaleYStart + - (mEdgeScaleYFinish - mEdgeScaleYStart) * - interp * factor; - mState = STATE_RECEDE; - break; - case STATE_RECEDE: - mState = STATE_IDLE; - break; - } - } - } - - private static class Drawable extends ResourceTexture { - private Rect mBounds = new Rect(); - private int mAlpha = 255; - - public Drawable(Context context, int resId) { - super(context, resId); - } - - public int getIntrinsicWidth() { - return getWidth(); - } - - public int getIntrinsicHeight() { - return getHeight(); - } - - public void setBounds(int left, int top, int right, int bottom) { - mBounds.set(left, top, right, bottom); - } - - public void setAlpha(int alpha) { - mAlpha = alpha; - } - - public void draw(GLCanvas canvas) { - canvas.save(GLCanvas.SAVE_FLAG_ALPHA); - canvas.multiplyAlpha(mAlpha / 255.0f); - Rect b = mBounds; - draw(canvas, b.left, b.top, b.width(), b.height()); - canvas.restore(); - } - } -} diff --git a/src/com/android/gallery3d/ui/EdgeView.java b/src/com/android/gallery3d/ui/EdgeView.java deleted file mode 100644 index 051de18fa..000000000 --- a/src/com/android/gallery3d/ui/EdgeView.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2011 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.ui; - -import android.content.Context; -import android.opengl.Matrix; - -import com.android.gallery3d.glrenderer.GLCanvas; - -// EdgeView draws EdgeEffect (blue glow) at four sides of the view. -public class EdgeView extends GLView { - @SuppressWarnings("unused") - private static final String TAG = "EdgeView"; - - public static final int INVALID_DIRECTION = -1; - public static final int TOP = 0; - public static final int LEFT = 1; - public static final int BOTTOM = 2; - public static final int RIGHT = 3; - - // Each edge effect has a transform matrix, and each matrix has 16 elements. - // We put all the elements in one array. These constants specify the - // starting index of each matrix. - private static final int TOP_M = TOP * 16; - private static final int LEFT_M = LEFT * 16; - private static final int BOTTOM_M = BOTTOM * 16; - private static final int RIGHT_M = RIGHT * 16; - - private EdgeEffect[] mEffect = new EdgeEffect[4]; - private float[] mMatrix = new float[4 * 16]; - - public EdgeView(Context context) { - for (int i = 0; i < 4; i++) { - mEffect[i] = new EdgeEffect(context); - } - } - - @Override - protected void onLayout( - boolean changeSize, int left, int top, int right, int bottom) { - if (!changeSize) return; - - int w = right - left; - int h = bottom - top; - for (int i = 0; i < 4; i++) { - if ((i & 1) == 0) { // top or bottom - mEffect[i].setSize(w, h); - } else { // left or right - mEffect[i].setSize(h, w); - } - } - - // Set up transforms for the four edges. Without transforms an - // EdgeEffect draws the TOP edge from (0, 0) to (w, Y * h) where Y - // is some factor < 1. For other edges we need to move, rotate, and - // flip the effects into proper places. - Matrix.setIdentityM(mMatrix, TOP_M); - Matrix.setIdentityM(mMatrix, LEFT_M); - Matrix.setIdentityM(mMatrix, BOTTOM_M); - Matrix.setIdentityM(mMatrix, RIGHT_M); - - Matrix.rotateM(mMatrix, LEFT_M, 90, 0, 0, 1); - Matrix.scaleM(mMatrix, LEFT_M, 1, -1, 1); - - Matrix.translateM(mMatrix, BOTTOM_M, 0, h, 0); - Matrix.scaleM(mMatrix, BOTTOM_M, 1, -1, 1); - - Matrix.translateM(mMatrix, RIGHT_M, w, 0, 0); - Matrix.rotateM(mMatrix, RIGHT_M, 90, 0, 0, 1); - } - - @Override - protected void render(GLCanvas canvas) { - super.render(canvas); - boolean more = false; - for (int i = 0; i < 4; i++) { - canvas.save(GLCanvas.SAVE_FLAG_MATRIX); - canvas.multiplyMatrix(mMatrix, i * 16); - more |= mEffect[i].draw(canvas); - canvas.restore(); - } - if (more) { - invalidate(); - } - } - - // Called when the content is pulled away from the edge. - // offset is in pixels. direction is one of {TOP, LEFT, BOTTOM, RIGHT}. - public void onPull(int offset, int direction) { - int fullLength = ((direction & 1) == 0) ? getWidth() : getHeight(); - mEffect[direction].onPull((float)offset / fullLength); - if (!mEffect[direction].isFinished()) { - invalidate(); - } - } - - // Call when the object is released after being pulled. - public void onRelease() { - boolean more = false; - for (int i = 0; i < 4; i++) { - mEffect[i].onRelease(); - more |= !mEffect[i].isFinished(); - } - if (more) { - invalidate(); - } - } - - // Call when the effect absorbs an impact at the given velocity. - // Used when a fling reaches the scroll boundary. velocity is in pixels - // per second. direction is one of {TOP, LEFT, BOTTOM, RIGHT}. - public void onAbsorb(int velocity, int direction) { - mEffect[direction].onAbsorb(velocity); - if (!mEffect[direction].isFinished()) { - invalidate(); - } - } -} diff --git a/src/com/android/gallery3d/ui/FlingScroller.java b/src/com/android/gallery3d/ui/FlingScroller.java deleted file mode 100644 index 6f98c64f9..000000000 --- a/src/com/android/gallery3d/ui/FlingScroller.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright (C) 2011 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.ui; - - -// This is a customized version of Scroller, with a interface similar to -// android.widget.Scroller. It does fling only, not scroll. -// -// The differences between the this Scroller and the system one are: -// -// (1) The velocity does not change because of min/max limit. -// (2) The duration is different. -// (3) The deceleration curve is different. -class FlingScroller { - @SuppressWarnings("unused") - private static final String TAG = "FlingController"; - - // The fling duration (in milliseconds) when velocity is 1 pixel/second - private static final float FLING_DURATION_PARAM = 50f; - private static final int DECELERATED_FACTOR = 4; - - private int mStartX, mStartY; - private int mMinX, mMinY, mMaxX, mMaxY; - private double mSinAngle; - private double mCosAngle; - private int mDuration; - private int mDistance; - private int mFinalX, mFinalY; - - private int mCurrX, mCurrY; - private double mCurrV; - - public int getFinalX() { - return mFinalX; - } - - public int getFinalY() { - return mFinalY; - } - - public int getDuration() { - return mDuration; - } - - public int getCurrX() { - return mCurrX; - - } - - public int getCurrY() { - return mCurrY; - } - - public int getCurrVelocityX() { - return (int)Math.round(mCurrV * mCosAngle); - } - - public int getCurrVelocityY() { - return (int)Math.round(mCurrV * mSinAngle); - } - - public void fling(int startX, int startY, int velocityX, int velocityY, - int minX, int maxX, int minY, int maxY) { - mStartX = startX; - mStartY = startY; - mMinX = minX; - mMinY = minY; - mMaxX = maxX; - mMaxY = maxY; - - double velocity = Math.hypot(velocityX, velocityY); - mSinAngle = velocityY / velocity; - mCosAngle = velocityX / velocity; - // - // The position formula: x(t) = s + (e - s) * (1 - (1 - t / T) ^ d) - // velocity formula: v(t) = d * (e - s) * (1 - t / T) ^ (d - 1) / T - // Thus, - // v0 = d * (e - s) / T => (e - s) = v0 * T / d - // - - // Ta = T_ref * (Va / V_ref) ^ (1 / (d - 1)); V_ref = 1 pixel/second; - mDuration = (int)Math.round(FLING_DURATION_PARAM - * Math.pow(Math.abs(velocity), 1.0 / (DECELERATED_FACTOR - 1))); - - // (e - s) = v0 * T / d - mDistance = (int)Math.round( - velocity * mDuration / DECELERATED_FACTOR / 1000); - - mFinalX = getX(1.0f); - mFinalY = getY(1.0f); - } - - public void computeScrollOffset(float progress) { - progress = Math.min(progress, 1); - float f = 1 - progress; - f = 1 - (float) Math.pow(f, DECELERATED_FACTOR); - mCurrX = getX(f); - mCurrY = getY(f); - mCurrV = getV(progress); - } - - private int getX(float f) { - int r = (int) Math.round(mStartX + f * mDistance * mCosAngle); - if (mCosAngle > 0 && mStartX <= mMaxX) { - r = Math.min(r, mMaxX); - } else if (mCosAngle < 0 && mStartX >= mMinX) { - r = Math.max(r, mMinX); - } - return r; - } - - private int getY(float f) { - int r = (int) Math.round(mStartY + f * mDistance * mSinAngle); - if (mSinAngle > 0 && mStartY <= mMaxY) { - r = Math.min(r, mMaxY); - } else if (mSinAngle < 0 && mStartY >= mMinY) { - r = Math.max(r, mMinY); - } - return r; - } - - private double getV(float progress) { - // velocity formula: v(t) = d * (e - s) * (1 - t / T) ^ (d - 1) / T - return DECELERATED_FACTOR * mDistance * 1000 * - Math.pow(1 - progress, DECELERATED_FACTOR - 1) / mDuration; - } -} diff --git a/src/com/android/gallery3d/ui/GLRoot.java b/src/com/android/gallery3d/ui/GLRoot.java deleted file mode 100644 index 33a82eaf7..000000000 --- a/src/com/android/gallery3d/ui/GLRoot.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.graphics.Matrix; - -import com.android.gallery3d.anim.CanvasAnimation; -import com.android.gallery3d.glrenderer.GLCanvas; - -public interface GLRoot { - - // Listener will be called when GL is idle AND before each frame. - // Mainly used for uploading textures. - public static interface OnGLIdleListener { - public boolean onGLIdle( - GLCanvas canvas, boolean renderRequested); - } - - public void addOnGLIdleListener(OnGLIdleListener listener); - public void registerLaunchedAnimation(CanvasAnimation animation); - public void requestRenderForced(); - public void requestRender(); - public void requestLayoutContentPane(); - - public void lockRenderThread(); - public void unlockRenderThread(); - - public void setContentPane(GLView content); - public void setOrientationSource(OrientationSource source); - public int getDisplayRotation(); - public int getCompensation(); - public Matrix getCompensationMatrix(); - public void freeze(); - public void unfreeze(); - public void setLightsOutMode(boolean enabled); - - public Context getContext(); -} diff --git a/src/com/android/gallery3d/ui/GLRootView.java b/src/com/android/gallery3d/ui/GLRootView.java deleted file mode 100644 index dc898d83d..000000000 --- a/src/com/android/gallery3d/ui/GLRootView.java +++ /dev/null @@ -1,630 +0,0 @@ -/* - * 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.ui; - -import android.annotation.TargetApi; -import android.content.Context; -import android.graphics.Matrix; -import android.graphics.PixelFormat; -import android.opengl.GLSurfaceView; -import android.os.Build; -import android.os.Process; -import android.os.SystemClock; -import android.util.AttributeSet; -import android.view.MotionEvent; -import android.view.SurfaceHolder; -import android.view.View; - -import com.android.gallery3d.R; -import com.android.gallery3d.anim.CanvasAnimation; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.glrenderer.BasicTexture; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.GLES11Canvas; -import com.android.gallery3d.glrenderer.GLES20Canvas; -import com.android.gallery3d.glrenderer.UploadedTexture; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.MotionEventHelper; -import com.android.gallery3d.util.Profile; - -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.ReentrantLock; - -import javax.microedition.khronos.egl.EGLConfig; -import javax.microedition.khronos.opengles.GL10; -import javax.microedition.khronos.opengles.GL11; - -// The root component of all <code>GLView</code>s. The rendering is done in GL -// thread while the event handling is done in the main thread. To synchronize -// the two threads, the entry points of this package need to synchronize on the -// <code>GLRootView</code> instance unless it can be proved that the rendering -// thread won't access the same thing as the method. The entry points include: -// (1) The public methods of HeadUpDisplay -// (2) The public methods of CameraHeadUpDisplay -// (3) The overridden methods in GLRootView. -public class GLRootView extends GLSurfaceView - implements GLSurfaceView.Renderer, GLRoot { - private static final String TAG = "GLRootView"; - - private static final boolean DEBUG_FPS = false; - private int mFrameCount = 0; - private long mFrameCountingStart = 0; - - private static final boolean DEBUG_INVALIDATE = false; - private int mInvalidateColor = 0; - - private static final boolean DEBUG_DRAWING_STAT = false; - - private static final boolean DEBUG_PROFILE = false; - private static final boolean DEBUG_PROFILE_SLOW_ONLY = false; - - private static final int FLAG_INITIALIZED = 1; - private static final int FLAG_NEED_LAYOUT = 2; - - private GL11 mGL; - private GLCanvas mCanvas; - private GLView mContentView; - - private OrientationSource mOrientationSource; - // mCompensation is the difference between the UI orientation on GLCanvas - // and the framework orientation. See OrientationManager for details. - private int mCompensation; - // mCompensationMatrix maps the coordinates of touch events. It is kept sync - // with mCompensation. - private Matrix mCompensationMatrix = new Matrix(); - private int mDisplayRotation; - - private int mFlags = FLAG_NEED_LAYOUT; - private volatile boolean mRenderRequested = false; - - private final ArrayList<CanvasAnimation> mAnimations = - new ArrayList<CanvasAnimation>(); - - private final ArrayDeque<OnGLIdleListener> mIdleListeners = - new ArrayDeque<OnGLIdleListener>(); - - private final IdleRunner mIdleRunner = new IdleRunner(); - - private final ReentrantLock mRenderLock = new ReentrantLock(); - private final Condition mFreezeCondition = - mRenderLock.newCondition(); - private boolean mFreeze; - - private long mLastDrawFinishTime; - private boolean mInDownState = false; - private boolean mFirstDraw = true; - - public GLRootView(Context context) { - this(context, null); - } - - public GLRootView(Context context, AttributeSet attrs) { - super(context, attrs); - mFlags |= FLAG_INITIALIZED; - setBackgroundDrawable(null); - setEGLContextClientVersion(ApiHelper.HAS_GLES20_REQUIRED ? 2 : 1); - if (ApiHelper.USE_888_PIXEL_FORMAT) { - setEGLConfigChooser(8, 8, 8, 0, 0, 0); - } else { - setEGLConfigChooser(5, 6, 5, 0, 0, 0); - } - setRenderer(this); - if (ApiHelper.USE_888_PIXEL_FORMAT) { - getHolder().setFormat(PixelFormat.RGB_888); - } else { - getHolder().setFormat(PixelFormat.RGB_565); - } - - // Uncomment this to enable gl error check. - // setDebugFlags(DEBUG_CHECK_GL_ERROR); - } - - @Override - public void registerLaunchedAnimation(CanvasAnimation animation) { - // Register the newly launched animation so that we can set the start - // time more precisely. (Usually, it takes much longer for first - // rendering, so we set the animation start time as the time we - // complete rendering) - mAnimations.add(animation); - } - - @Override - public void addOnGLIdleListener(OnGLIdleListener listener) { - synchronized (mIdleListeners) { - mIdleListeners.addLast(listener); - mIdleRunner.enable(); - } - } - - @Override - public void setContentPane(GLView content) { - if (mContentView == content) return; - if (mContentView != null) { - if (mInDownState) { - long now = SystemClock.uptimeMillis(); - MotionEvent cancelEvent = MotionEvent.obtain( - now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0); - mContentView.dispatchTouchEvent(cancelEvent); - cancelEvent.recycle(); - mInDownState = false; - } - mContentView.detachFromRoot(); - BasicTexture.yieldAllTextures(); - } - mContentView = content; - if (content != null) { - content.attachToRoot(this); - requestLayoutContentPane(); - } - } - - @Override - public void requestRenderForced() { - superRequestRender(); - } - - @Override - public void requestRender() { - if (DEBUG_INVALIDATE) { - StackTraceElement e = Thread.currentThread().getStackTrace()[4]; - String caller = e.getFileName() + ":" + e.getLineNumber() + " "; - Log.d(TAG, "invalidate: " + caller); - } - if (mRenderRequested) return; - mRenderRequested = true; - if (ApiHelper.HAS_POST_ON_ANIMATION) { - postOnAnimation(mRequestRenderOnAnimationFrame); - } else { - super.requestRender(); - } - } - - private Runnable mRequestRenderOnAnimationFrame = new Runnable() { - @Override - public void run() { - superRequestRender(); - } - }; - - private void superRequestRender() { - super.requestRender(); - } - - @Override - public void requestLayoutContentPane() { - mRenderLock.lock(); - try { - if (mContentView == null || (mFlags & FLAG_NEED_LAYOUT) != 0) return; - - // "View" system will invoke onLayout() for initialization(bug ?), we - // have to ignore it since the GLThread is not ready yet. - if ((mFlags & FLAG_INITIALIZED) == 0) return; - - mFlags |= FLAG_NEED_LAYOUT; - requestRender(); - } finally { - mRenderLock.unlock(); - } - } - - private void layoutContentPane() { - mFlags &= ~FLAG_NEED_LAYOUT; - - int w = getWidth(); - int h = getHeight(); - int displayRotation = 0; - int compensation = 0; - - // Get the new orientation values - if (mOrientationSource != null) { - displayRotation = mOrientationSource.getDisplayRotation(); - compensation = mOrientationSource.getCompensation(); - } else { - displayRotation = 0; - compensation = 0; - } - - if (mCompensation != compensation) { - mCompensation = compensation; - if (mCompensation % 180 != 0) { - mCompensationMatrix.setRotate(mCompensation); - // move center to origin before rotation - mCompensationMatrix.preTranslate(-w / 2, -h / 2); - // align with the new origin after rotation - mCompensationMatrix.postTranslate(h / 2, w / 2); - } else { - mCompensationMatrix.setRotate(mCompensation, w / 2, h / 2); - } - } - mDisplayRotation = displayRotation; - - // Do the actual layout. - if (mCompensation % 180 != 0) { - int tmp = w; - w = h; - h = tmp; - } - Log.i(TAG, "layout content pane " + w + "x" + h - + " (compensation " + mCompensation + ")"); - if (mContentView != null && w != 0 && h != 0) { - mContentView.layout(0, 0, w, h); - } - // Uncomment this to dump the view hierarchy. - //mContentView.dumpTree(""); - } - - @Override - protected void onLayout( - boolean changed, int left, int top, int right, int bottom) { - if (changed) requestLayoutContentPane(); - } - - /** - * Called when the context is created, possibly after automatic destruction. - */ - // This is a GLSurfaceView.Renderer callback - @Override - public void onSurfaceCreated(GL10 gl1, EGLConfig config) { - GL11 gl = (GL11) gl1; - if (mGL != null) { - // The GL Object has changed - Log.i(TAG, "GLObject has changed from " + mGL + " to " + gl); - } - mRenderLock.lock(); - try { - mGL = gl; - mCanvas = ApiHelper.HAS_GLES20_REQUIRED ? new GLES20Canvas() : new GLES11Canvas(gl); - BasicTexture.invalidateAllTextures(); - } finally { - mRenderLock.unlock(); - } - - if (DEBUG_FPS || DEBUG_PROFILE) { - setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY); - } else { - setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); - } - } - - /** - * Called when the OpenGL surface is recreated without destroying the - * context. - */ - // This is a GLSurfaceView.Renderer callback - @Override - public void onSurfaceChanged(GL10 gl1, int width, int height) { - Log.i(TAG, "onSurfaceChanged: " + width + "x" + height - + ", gl10: " + gl1.toString()); - Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY); - GalleryUtils.setRenderThread(); - if (DEBUG_PROFILE) { - Log.d(TAG, "Start profiling"); - Profile.enable(20); // take a sample every 20ms - } - GL11 gl = (GL11) gl1; - Utils.assertTrue(mGL == gl); - - mCanvas.setSize(width, height); - } - - private void outputFps() { - long now = System.nanoTime(); - if (mFrameCountingStart == 0) { - mFrameCountingStart = now; - } else if ((now - mFrameCountingStart) > 1000000000) { - Log.d(TAG, "fps: " + (double) mFrameCount - * 1000000000 / (now - mFrameCountingStart)); - mFrameCountingStart = now; - mFrameCount = 0; - } - ++mFrameCount; - } - - @Override - public void onDrawFrame(GL10 gl) { - AnimationTime.update(); - long t0; - if (DEBUG_PROFILE_SLOW_ONLY) { - Profile.hold(); - t0 = System.nanoTime(); - } - mRenderLock.lock(); - - while (mFreeze) { - mFreezeCondition.awaitUninterruptibly(); - } - - try { - onDrawFrameLocked(gl); - } finally { - mRenderLock.unlock(); - } - - // We put a black cover View in front of the SurfaceView and hide it - // after the first draw. This prevents the SurfaceView being transparent - // before the first draw. - if (mFirstDraw) { - mFirstDraw = false; - post(new Runnable() { - @Override - public void run() { - View root = getRootView(); - View cover = root.findViewById(R.id.gl_root_cover); - cover.setVisibility(GONE); - } - }); - } - - if (DEBUG_PROFILE_SLOW_ONLY) { - long t = System.nanoTime(); - long durationInMs = (t - mLastDrawFinishTime) / 1000000; - long durationDrawInMs = (t - t0) / 1000000; - mLastDrawFinishTime = t; - - if (durationInMs > 34) { // 34ms -> we skipped at least 2 frames - Log.v(TAG, "----- SLOW (" + durationDrawInMs + "/" + - durationInMs + ") -----"); - Profile.commit(); - } else { - Profile.drop(); - } - } - } - - private void onDrawFrameLocked(GL10 gl) { - if (DEBUG_FPS) outputFps(); - - // release the unbound textures and deleted buffers. - mCanvas.deleteRecycledResources(); - - // reset texture upload limit - UploadedTexture.resetUploadLimit(); - - mRenderRequested = false; - - if ((mOrientationSource != null - && mDisplayRotation != mOrientationSource.getDisplayRotation()) - || (mFlags & FLAG_NEED_LAYOUT) != 0) { - layoutContentPane(); - } - - mCanvas.save(GLCanvas.SAVE_FLAG_ALL); - rotateCanvas(-mCompensation); - if (mContentView != null) { - mContentView.render(mCanvas); - } else { - // Make sure we always draw something to prevent displaying garbage - mCanvas.clearBuffer(); - } - mCanvas.restore(); - - if (!mAnimations.isEmpty()) { - long now = AnimationTime.get(); - for (int i = 0, n = mAnimations.size(); i < n; i++) { - mAnimations.get(i).setStartTime(now); - } - mAnimations.clear(); - } - - if (UploadedTexture.uploadLimitReached()) { - requestRender(); - } - - synchronized (mIdleListeners) { - if (!mIdleListeners.isEmpty()) mIdleRunner.enable(); - } - - if (DEBUG_INVALIDATE) { - mCanvas.fillRect(10, 10, 5, 5, mInvalidateColor); - mInvalidateColor = ~mInvalidateColor; - } - - if (DEBUG_DRAWING_STAT) { - mCanvas.dumpStatisticsAndClear(); - } - } - - private void rotateCanvas(int degrees) { - if (degrees == 0) return; - int w = getWidth(); - int h = getHeight(); - int cx = w / 2; - int cy = h / 2; - mCanvas.translate(cx, cy); - mCanvas.rotate(degrees, 0, 0, 1); - if (degrees % 180 != 0) { - mCanvas.translate(-cy, -cx); - } else { - mCanvas.translate(-cx, -cy); - } - } - - @Override - public boolean dispatchTouchEvent(MotionEvent event) { - if (!isEnabled()) return false; - - int action = event.getAction(); - if (action == MotionEvent.ACTION_CANCEL - || action == MotionEvent.ACTION_UP) { - mInDownState = false; - } else if (!mInDownState && action != MotionEvent.ACTION_DOWN) { - return false; - } - - if (mCompensation != 0) { - event = MotionEventHelper.transformEvent(event, mCompensationMatrix); - } - - mRenderLock.lock(); - try { - // If this has been detached from root, we don't need to handle event - boolean handled = mContentView != null - && mContentView.dispatchTouchEvent(event); - if (action == MotionEvent.ACTION_DOWN && handled) { - mInDownState = true; - } - return handled; - } finally { - mRenderLock.unlock(); - } - } - - private class IdleRunner implements Runnable { - // true if the idle runner is in the queue - private boolean mActive = false; - - @Override - public void run() { - OnGLIdleListener listener; - synchronized (mIdleListeners) { - mActive = false; - if (mIdleListeners.isEmpty()) return; - listener = mIdleListeners.removeFirst(); - } - mRenderLock.lock(); - boolean keepInQueue; - try { - keepInQueue = listener.onGLIdle(mCanvas, mRenderRequested); - } finally { - mRenderLock.unlock(); - } - synchronized (mIdleListeners) { - if (keepInQueue) mIdleListeners.addLast(listener); - if (!mRenderRequested && !mIdleListeners.isEmpty()) enable(); - } - } - - public void enable() { - // Who gets the flag can add it to the queue - if (mActive) return; - mActive = true; - queueEvent(this); - } - } - - @Override - public void lockRenderThread() { - mRenderLock.lock(); - } - - @Override - public void unlockRenderThread() { - mRenderLock.unlock(); - } - - @Override - public void onPause() { - unfreeze(); - super.onPause(); - if (DEBUG_PROFILE) { - Log.d(TAG, "Stop profiling"); - Profile.disableAll(); - Profile.dumpToFile("/sdcard/gallery.prof"); - Profile.reset(); - } - } - - @Override - public void setOrientationSource(OrientationSource source) { - mOrientationSource = source; - } - - @Override - public int getDisplayRotation() { - return mDisplayRotation; - } - - @Override - public int getCompensation() { - return mCompensation; - } - - @Override - public Matrix getCompensationMatrix() { - return mCompensationMatrix; - } - - @Override - public void freeze() { - mRenderLock.lock(); - mFreeze = true; - mRenderLock.unlock(); - } - - @Override - public void unfreeze() { - mRenderLock.lock(); - mFreeze = false; - mFreezeCondition.signalAll(); - mRenderLock.unlock(); - } - - @Override - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - public void setLightsOutMode(boolean enabled) { - if (!ApiHelper.HAS_SET_SYSTEM_UI_VISIBILITY) return; - - int flags = 0; - if (enabled) { - flags = STATUS_BAR_HIDDEN; - if (ApiHelper.HAS_VIEW_SYSTEM_UI_FLAG_LAYOUT_STABLE) { - flags |= (SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_STABLE); - } - } - setSystemUiVisibility(flags); - } - - // We need to unfreeze in the following methods and in onPause(). - // These methods will wait on GLThread. If we have freezed the GLRootView, - // the GLThread will wait on main thread to call unfreeze and cause dead - // lock. - @Override - public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - unfreeze(); - super.surfaceChanged(holder, format, w, h); - } - - @Override - public void surfaceCreated(SurfaceHolder holder) { - unfreeze(); - super.surfaceCreated(holder); - } - - @Override - public void surfaceDestroyed(SurfaceHolder holder) { - unfreeze(); - super.surfaceDestroyed(holder); - } - - @Override - protected void onDetachedFromWindow() { - unfreeze(); - super.onDetachedFromWindow(); - } - - @Override - protected void finalize() throws Throwable { - try { - unfreeze(); - } finally { - super.finalize(); - } - } -} diff --git a/src/com/android/gallery3d/ui/GLView.java b/src/com/android/gallery3d/ui/GLView.java deleted file mode 100644 index 83de19fe4..000000000 --- a/src/com/android/gallery3d/ui/GLView.java +++ /dev/null @@ -1,465 +0,0 @@ -/* - * 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.ui; - -import android.graphics.Rect; -import android.os.SystemClock; -import android.view.MotionEvent; - -import com.android.gallery3d.anim.CanvasAnimation; -import com.android.gallery3d.anim.StateTransitionAnimation; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.glrenderer.GLCanvas; - -import java.util.ArrayList; - -// GLView is a UI component. It can render to a GLCanvas and accept touch -// events. A GLView may have zero or more child GLView and they form a tree -// structure. The rendering and event handling will pass through the tree -// structure. -// -// A GLView tree should be attached to a GLRoot before event dispatching and -// rendering happens. GLView asks GLRoot to re-render or re-layout the -// GLView hierarchy using requestRender() and requestLayoutContentPane(). -// -// The render() method is called in a separate thread. Before calling -// dispatchTouchEvent() and layout(), GLRoot acquires a lock to avoid the -// rendering thread running at the same time. If there are other entry points -// from main thread (like a Handler) in your GLView, you need to call -// lockRendering() if the rendering thread should not run at the same time. -// -public class GLView { - private static final String TAG = "GLView"; - - public static final int VISIBLE = 0; - public static final int INVISIBLE = 1; - - private static final int FLAG_INVISIBLE = 1; - private static final int FLAG_SET_MEASURED_SIZE = 2; - private static final int FLAG_LAYOUT_REQUESTED = 4; - - public interface OnClickListener { - void onClick(GLView v); - } - - protected final Rect mBounds = new Rect(); - protected final Rect mPaddings = new Rect(); - - private GLRoot mRoot; - protected GLView mParent; - private ArrayList<GLView> mComponents; - private GLView mMotionTarget; - - private CanvasAnimation mAnimation; - - private int mViewFlags = 0; - - protected int mMeasuredWidth = 0; - protected int mMeasuredHeight = 0; - - private int mLastWidthSpec = -1; - private int mLastHeightSpec = -1; - - protected int mScrollY = 0; - protected int mScrollX = 0; - protected int mScrollHeight = 0; - protected int mScrollWidth = 0; - - private float [] mBackgroundColor; - private StateTransitionAnimation mTransition; - - public void startAnimation(CanvasAnimation animation) { - GLRoot root = getGLRoot(); - if (root == null) throw new IllegalStateException(); - mAnimation = animation; - if (mAnimation != null) { - mAnimation.start(); - root.registerLaunchedAnimation(mAnimation); - } - invalidate(); - } - - // Sets the visiblity of this GLView (either GLView.VISIBLE or - // GLView.INVISIBLE). - public void setVisibility(int visibility) { - if (visibility == getVisibility()) return; - if (visibility == VISIBLE) { - mViewFlags &= ~FLAG_INVISIBLE; - } else { - mViewFlags |= FLAG_INVISIBLE; - } - onVisibilityChanged(visibility); - invalidate(); - } - - // Returns GLView.VISIBLE or GLView.INVISIBLE - public int getVisibility() { - return (mViewFlags & FLAG_INVISIBLE) == 0 ? VISIBLE : INVISIBLE; - } - - // This should only be called on the content pane (the topmost GLView). - public void attachToRoot(GLRoot root) { - Utils.assertTrue(mParent == null && mRoot == null); - onAttachToRoot(root); - } - - // This should only be called on the content pane (the topmost GLView). - public void detachFromRoot() { - Utils.assertTrue(mParent == null && mRoot != null); - onDetachFromRoot(); - } - - // Returns the number of children of the GLView. - public int getComponentCount() { - return mComponents == null ? 0 : mComponents.size(); - } - - // Returns the children for the given index. - public GLView getComponent(int index) { - if (mComponents == null) { - throw new ArrayIndexOutOfBoundsException(index); - } - return mComponents.get(index); - } - - // Adds a child to this GLView. - public void addComponent(GLView component) { - // Make sure the component doesn't have a parent currently. - if (component.mParent != null) throw new IllegalStateException(); - - // Build parent-child links - if (mComponents == null) { - mComponents = new ArrayList<GLView>(); - } - mComponents.add(component); - component.mParent = this; - - // If this is added after we have a root, tell the component. - if (mRoot != null) { - component.onAttachToRoot(mRoot); - } - } - - // Removes a child from this GLView. - public boolean removeComponent(GLView component) { - if (mComponents == null) return false; - if (mComponents.remove(component)) { - removeOneComponent(component); - return true; - } - return false; - } - - // Removes all children of this GLView. - public void removeAllComponents() { - for (int i = 0, n = mComponents.size(); i < n; ++i) { - removeOneComponent(mComponents.get(i)); - } - mComponents.clear(); - } - - private void removeOneComponent(GLView component) { - if (mMotionTarget == component) { - long now = SystemClock.uptimeMillis(); - MotionEvent cancelEvent = MotionEvent.obtain( - now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0); - dispatchTouchEvent(cancelEvent); - cancelEvent.recycle(); - } - component.onDetachFromRoot(); - component.mParent = null; - } - - public Rect bounds() { - return mBounds; - } - - public int getWidth() { - return mBounds.right - mBounds.left; - } - - public int getHeight() { - return mBounds.bottom - mBounds.top; - } - - public GLRoot getGLRoot() { - return mRoot; - } - - // Request re-rendering of the view hierarchy. - // This is used for animation or when the contents changed. - public void invalidate() { - GLRoot root = getGLRoot(); - if (root != null) root.requestRender(); - } - - // Request re-layout of the view hierarchy. - public void requestLayout() { - mViewFlags |= FLAG_LAYOUT_REQUESTED; - mLastHeightSpec = -1; - mLastWidthSpec = -1; - if (mParent != null) { - mParent.requestLayout(); - } else { - // Is this a content pane ? - GLRoot root = getGLRoot(); - if (root != null) root.requestLayoutContentPane(); - } - } - - protected void render(GLCanvas canvas) { - boolean transitionActive = false; - if (mTransition != null && mTransition.calculate(AnimationTime.get())) { - invalidate(); - transitionActive = mTransition.isActive(); - } - renderBackground(canvas); - canvas.save(); - if (transitionActive) { - mTransition.applyContentTransform(this, canvas); - } - for (int i = 0, n = getComponentCount(); i < n; ++i) { - renderChild(canvas, getComponent(i)); - } - canvas.restore(); - if (transitionActive) { - mTransition.applyOverlay(this, canvas); - } - } - - public void setIntroAnimation(StateTransitionAnimation intro) { - mTransition = intro; - if (mTransition != null) mTransition.start(); - } - - public float [] getBackgroundColor() { - return mBackgroundColor; - } - - public void setBackgroundColor(float [] color) { - mBackgroundColor = color; - } - - protected void renderBackground(GLCanvas view) { - if (mBackgroundColor != null) { - view.clearBuffer(mBackgroundColor); - } - if (mTransition != null && mTransition.isActive()) { - mTransition.applyBackground(this, view); - return; - } - } - - protected void renderChild(GLCanvas canvas, GLView component) { - if (component.getVisibility() != GLView.VISIBLE - && component.mAnimation == null) return; - - int xoffset = component.mBounds.left - mScrollX; - int yoffset = component.mBounds.top - mScrollY; - - canvas.translate(xoffset, yoffset); - - CanvasAnimation anim = component.mAnimation; - if (anim != null) { - canvas.save(anim.getCanvasSaveFlags()); - if (anim.calculate(AnimationTime.get())) { - invalidate(); - } else { - component.mAnimation = null; - } - anim.apply(canvas); - } - component.render(canvas); - if (anim != null) canvas.restore(); - canvas.translate(-xoffset, -yoffset); - } - - protected boolean onTouch(MotionEvent event) { - return false; - } - - protected boolean dispatchTouchEvent(MotionEvent event, - int x, int y, GLView component, boolean checkBounds) { - Rect rect = component.mBounds; - int left = rect.left; - int top = rect.top; - if (!checkBounds || rect.contains(x, y)) { - event.offsetLocation(-left, -top); - if (component.dispatchTouchEvent(event)) { - event.offsetLocation(left, top); - return true; - } - event.offsetLocation(left, top); - } - return false; - } - - protected boolean dispatchTouchEvent(MotionEvent event) { - int x = (int) event.getX(); - int y = (int) event.getY(); - int action = event.getAction(); - if (mMotionTarget != null) { - if (action == MotionEvent.ACTION_DOWN) { - MotionEvent cancel = MotionEvent.obtain(event); - cancel.setAction(MotionEvent.ACTION_CANCEL); - dispatchTouchEvent(cancel, x, y, mMotionTarget, false); - mMotionTarget = null; - } else { - dispatchTouchEvent(event, x, y, mMotionTarget, false); - if (action == MotionEvent.ACTION_CANCEL - || action == MotionEvent.ACTION_UP) { - mMotionTarget = null; - } - return true; - } - } - if (action == MotionEvent.ACTION_DOWN) { - // in the reverse rendering order - for (int i = getComponentCount() - 1; i >= 0; --i) { - GLView component = getComponent(i); - if (component.getVisibility() != GLView.VISIBLE) continue; - if (dispatchTouchEvent(event, x, y, component, true)) { - mMotionTarget = component; - return true; - } - } - } - return onTouch(event); - } - - public Rect getPaddings() { - return mPaddings; - } - - public void layout(int left, int top, int right, int bottom) { - boolean sizeChanged = setBounds(left, top, right, bottom); - mViewFlags &= ~FLAG_LAYOUT_REQUESTED; - // We call onLayout no matter sizeChanged is true or not because the - // orientation may change without changing the size of the View (for - // example, rotate the device by 180 degrees), and we want to handle - // orientation change in onLayout. - onLayout(sizeChanged, left, top, right, bottom); - } - - private boolean setBounds(int left, int top, int right, int bottom) { - boolean sizeChanged = (right - left) != (mBounds.right - mBounds.left) - || (bottom - top) != (mBounds.bottom - mBounds.top); - mBounds.set(left, top, right, bottom); - return sizeChanged; - } - - public void measure(int widthSpec, int heightSpec) { - if (widthSpec == mLastWidthSpec && heightSpec == mLastHeightSpec - && (mViewFlags & FLAG_LAYOUT_REQUESTED) == 0) { - return; - } - - mLastWidthSpec = widthSpec; - mLastHeightSpec = heightSpec; - - mViewFlags &= ~FLAG_SET_MEASURED_SIZE; - onMeasure(widthSpec, heightSpec); - if ((mViewFlags & FLAG_SET_MEASURED_SIZE) == 0) { - throw new IllegalStateException(getClass().getName() - + " should call setMeasuredSize() in onMeasure()"); - } - } - - protected void onMeasure(int widthSpec, int heightSpec) { - } - - protected void setMeasuredSize(int width, int height) { - mViewFlags |= FLAG_SET_MEASURED_SIZE; - mMeasuredWidth = width; - mMeasuredHeight = height; - } - - public int getMeasuredWidth() { - return mMeasuredWidth; - } - - public int getMeasuredHeight() { - return mMeasuredHeight; - } - - protected void onLayout( - boolean changeSize, int left, int top, int right, int bottom) { - } - - /** - * Gets the bounds of the given descendant that relative to this view. - */ - public boolean getBoundsOf(GLView descendant, Rect out) { - int xoffset = 0; - int yoffset = 0; - GLView view = descendant; - while (view != this) { - if (view == null) return false; - Rect bounds = view.mBounds; - xoffset += bounds.left; - yoffset += bounds.top; - view = view.mParent; - } - out.set(xoffset, yoffset, xoffset + descendant.getWidth(), - yoffset + descendant.getHeight()); - return true; - } - - protected void onVisibilityChanged(int visibility) { - for (int i = 0, n = getComponentCount(); i < n; ++i) { - GLView child = getComponent(i); - if (child.getVisibility() == GLView.VISIBLE) { - child.onVisibilityChanged(visibility); - } - } - } - - protected void onAttachToRoot(GLRoot root) { - mRoot = root; - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).onAttachToRoot(root); - } - } - - protected void onDetachFromRoot() { - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).onDetachFromRoot(); - } - mRoot = null; - } - - public void lockRendering() { - if (mRoot != null) { - mRoot.lockRenderThread(); - } - } - - public void unlockRendering() { - if (mRoot != null) { - mRoot.unlockRenderThread(); - } - } - - // This is for debugging only. - // Dump the view hierarchy into log. - void dumpTree(String prefix) { - Log.d(TAG, prefix + getClass().getSimpleName()); - for (int i = 0, n = getComponentCount(); i < n; ++i) { - getComponent(i).dumpTree(prefix + "...."); - } - } -} diff --git a/src/com/android/gallery3d/ui/GestureRecognizer.java b/src/com/android/gallery3d/ui/GestureRecognizer.java deleted file mode 100644 index 1e5250b9b..000000000 --- a/src/com/android/gallery3d/ui/GestureRecognizer.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.content.Context; -import android.os.SystemClock; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.ScaleGestureDetector; - -// This class aggregates three gesture detectors: GestureDetector, -// ScaleGestureDetector, and DownUpDetector. -public class GestureRecognizer { - @SuppressWarnings("unused") - private static final String TAG = "GestureRecognizer"; - - public interface Listener { - boolean onSingleTapUp(float x, float y); - boolean onDoubleTap(float x, float y); - boolean onScroll(float dx, float dy, float totalX, float totalY); - boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY); - boolean onScaleBegin(float focusX, float focusY); - boolean onScale(float focusX, float focusY, float scale); - void onScaleEnd(); - void onDown(float x, float y); - void onUp(); - } - - private final GestureDetector mGestureDetector; - private final ScaleGestureDetector mScaleDetector; - private final DownUpDetector mDownUpDetector; - private final Listener mListener; - - public GestureRecognizer(Context context, Listener listener) { - mListener = listener; - mGestureDetector = new GestureDetector(context, new MyGestureListener(), - null, true /* ignoreMultitouch */); - mScaleDetector = new ScaleGestureDetector( - context, new MyScaleListener()); - mDownUpDetector = new DownUpDetector(new MyDownUpListener()); - } - - public void onTouchEvent(MotionEvent event) { - mGestureDetector.onTouchEvent(event); - mScaleDetector.onTouchEvent(event); - mDownUpDetector.onTouchEvent(event); - } - - public boolean isDown() { - return mDownUpDetector.isDown(); - } - - public void cancelScale() { - long now = SystemClock.uptimeMillis(); - MotionEvent cancelEvent = MotionEvent.obtain( - now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0); - mScaleDetector.onTouchEvent(cancelEvent); - cancelEvent.recycle(); - } - - private class MyGestureListener - extends GestureDetector.SimpleOnGestureListener { - @Override - public boolean onSingleTapUp(MotionEvent e) { - return mListener.onSingleTapUp(e.getX(), e.getY()); - } - - @Override - public boolean onDoubleTap(MotionEvent e) { - return mListener.onDoubleTap(e.getX(), e.getY()); - } - - @Override - public boolean onScroll( - MotionEvent e1, MotionEvent e2, float dx, float dy) { - return mListener.onScroll( - dx, dy, e2.getX() - e1.getX(), e2.getY() - e1.getY()); - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, - float velocityY) { - return mListener.onFling(e1, e2, velocityX, velocityY); - } - } - - private class MyScaleListener - extends ScaleGestureDetector.SimpleOnScaleGestureListener { - @Override - public boolean onScaleBegin(ScaleGestureDetector detector) { - return mListener.onScaleBegin( - detector.getFocusX(), detector.getFocusY()); - } - - @Override - public boolean onScale(ScaleGestureDetector detector) { - return mListener.onScale(detector.getFocusX(), - detector.getFocusY(), detector.getScaleFactor()); - } - - @Override - public void onScaleEnd(ScaleGestureDetector detector) { - mListener.onScaleEnd(); - } - } - - private class MyDownUpListener implements DownUpDetector.DownUpListener { - @Override - public void onDown(MotionEvent e) { - mListener.onDown(e.getX(), e.getY()); - } - - @Override - public void onUp(MotionEvent e) { - mListener.onUp(); - } - } -} diff --git a/src/com/android/gallery3d/ui/Log.java b/src/com/android/gallery3d/ui/Log.java deleted file mode 100644 index 5570763bb..000000000 --- a/src/com/android/gallery3d/ui/Log.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.ui; - -// TODO: Delete this -public class Log { - public static int v(String tag, String msg) { - return android.util.Log.v(tag, msg); - } - public static int v(String tag, String msg, Throwable tr) { - return android.util.Log.v(tag, msg, tr); - } - public static int d(String tag, String msg) { - return android.util.Log.d(tag, msg); - } - public static int d(String tag, String msg, Throwable tr) { - return android.util.Log.d(tag, msg, tr); - } - public static int i(String tag, String msg) { - return android.util.Log.i(tag, msg); - } - public static int i(String tag, String msg, Throwable tr) { - return android.util.Log.i(tag, msg, tr); - } - public static int w(String tag, String msg) { - return android.util.Log.w(tag, msg); - } - public static int w(String tag, String msg, Throwable tr) { - return android.util.Log.w(tag, msg, tr); - } - public static int w(String tag, Throwable tr) { - return android.util.Log.w(tag, tr); - } - public static int e(String tag, String msg) { - return android.util.Log.e(tag, msg); - } - public static int e(String tag, String msg, Throwable tr) { - return android.util.Log.e(tag, msg, tr); - } -} diff --git a/src/com/android/gallery3d/ui/ManageCacheDrawer.java b/src/com/android/gallery3d/ui/ManageCacheDrawer.java deleted file mode 100644 index d210bd1f1..000000000 --- a/src/com/android/gallery3d/ui/ManageCacheDrawer.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; - -import com.android.gallery3d.R; -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.data.DataSourceType; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.ResourceTexture; -import com.android.gallery3d.glrenderer.StringTexture; -import com.android.gallery3d.ui.AlbumSetSlidingWindow.AlbumSetEntry; - -public class ManageCacheDrawer extends AlbumSetSlotRenderer { - private final ResourceTexture mCheckedItem; - private final ResourceTexture mUnCheckedItem; - private final SelectionManager mSelectionManager; - - private final ResourceTexture mLocalAlbumIcon; - private final StringTexture mCachingText; - - private final int mCachePinSize; - private final int mCachePinMargin; - - public ManageCacheDrawer(AbstractGalleryActivity activity, SelectionManager selectionManager, - SlotView slotView, LabelSpec labelSpec, int cachePinSize, int cachePinMargin) { - super(activity, selectionManager, slotView, labelSpec, - activity.getResources().getColor(R.color.cache_placeholder)); - Context context = activity; - mCheckedItem = new ResourceTexture( - context, R.drawable.btn_make_offline_normal_on_holo_dark); - mUnCheckedItem = new ResourceTexture( - context, R.drawable.btn_make_offline_normal_off_holo_dark); - mLocalAlbumIcon = new ResourceTexture( - context, R.drawable.btn_make_offline_disabled_on_holo_dark); - String cachingLabel = context.getString(R.string.caching_label); - mCachingText = StringTexture.newInstance(cachingLabel, 12, 0xffffffff); - mSelectionManager = selectionManager; - mCachePinSize = cachePinSize; - mCachePinMargin = cachePinMargin; - } - - private static boolean isLocal(int dataSourceType) { - return dataSourceType != DataSourceType.TYPE_PICASA; - } - - @Override - public int renderSlot(GLCanvas canvas, int index, int pass, int width, int height) { - AlbumSetEntry entry = mDataWindow.get(index); - - boolean wantCache = entry.cacheFlag == MediaSet.CACHE_FLAG_FULL; - boolean isCaching = wantCache && ( - entry.cacheStatus != MediaSet.CACHE_STATUS_CACHED_FULL); - boolean selected = mSelectionManager.isItemSelected(entry.setPath); - boolean chooseToCache = wantCache ^ selected; - boolean available = isLocal(entry.sourceType) || chooseToCache; - - int renderRequestFlags = 0; - - if (!available) { - canvas.save(GLCanvas.SAVE_FLAG_ALPHA); - canvas.multiplyAlpha(0.6f); - } - renderRequestFlags |= renderContent(canvas, entry, width, height); - if (!available) canvas.restore(); - - renderRequestFlags |= renderLabel(canvas, entry, width, height); - - drawCachingPin(canvas, entry.setPath, - entry.sourceType, isCaching, chooseToCache, width, height); - - renderRequestFlags |= renderOverlay(canvas, index, entry, width, height); - return renderRequestFlags; - } - - private void drawCachingPin(GLCanvas canvas, Path path, int dataSourceType, - boolean isCaching, boolean chooseToCache, int width, int height) { - ResourceTexture icon; - if (isLocal(dataSourceType)) { - icon = mLocalAlbumIcon; - } else if (chooseToCache) { - icon = mCheckedItem; - } else { - icon = mUnCheckedItem; - } - - // show the icon in right bottom - int s = mCachePinSize; - int m = mCachePinMargin; - icon.draw(canvas, width - m - s, height - s, s, s); - - if (isCaching) { - int w = mCachingText.getWidth(); - int h = mCachingText.getHeight(); - // Show the caching text in bottom center - mCachingText.draw(canvas, (width - w) / 2, height - h); - } - } -} diff --git a/src/com/android/gallery3d/ui/MeasureHelper.java b/src/com/android/gallery3d/ui/MeasureHelper.java deleted file mode 100644 index f65dc10b3..000000000 --- a/src/com/android/gallery3d/ui/MeasureHelper.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.ui; - -import android.graphics.Rect; -import android.view.View.MeasureSpec; - -class MeasureHelper { - - private static MeasureHelper sInstance = new MeasureHelper(null); - - private GLView mComponent; - private int mPreferredWidth; - private int mPreferredHeight; - - private MeasureHelper(GLView component) { - mComponent = component; - } - - public static MeasureHelper getInstance(GLView component) { - sInstance.mComponent = component; - return sInstance; - } - - public MeasureHelper setPreferredContentSize(int width, int height) { - mPreferredWidth = width; - mPreferredHeight = height; - return this; - } - - public void measure(int widthSpec, int heightSpec) { - Rect p = mComponent.getPaddings(); - setMeasuredSize( - getLength(widthSpec, mPreferredWidth + p.left + p.right), - getLength(heightSpec, mPreferredHeight + p.top + p.bottom)); - } - - private static int getLength(int measureSpec, int prefered) { - int specLength = MeasureSpec.getSize(measureSpec); - switch(MeasureSpec.getMode(measureSpec)) { - case MeasureSpec.EXACTLY: return specLength; - case MeasureSpec.AT_MOST: return Math.min(prefered, specLength); - default: return prefered; - } - } - - protected void setMeasuredSize(int width, int height) { - mComponent.setMeasuredSize(width, height); - } - -} diff --git a/src/com/android/gallery3d/ui/MenuExecutor.java b/src/com/android/gallery3d/ui/MenuExecutor.java deleted file mode 100644 index 29def0527..000000000 --- a/src/com/android/gallery3d/ui/MenuExecutor.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * 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.ui; - -import android.app.Activity; -import android.app.AlertDialog; -import android.app.ProgressDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.DialogInterface.OnCancelListener; -import android.content.DialogInterface.OnClickListener; -import android.content.Intent; -import android.os.Handler; -import android.os.Message; -import android.view.Menu; -import android.view.MenuItem; - -import com.android.gallery3d.R; -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.filtershow.crop.CropActivity; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.ThreadPool.Job; -import com.android.gallery3d.util.ThreadPool.JobContext; - -import java.util.ArrayList; - -public class MenuExecutor { - @SuppressWarnings("unused") - private static final String TAG = "MenuExecutor"; - - private static final int MSG_TASK_COMPLETE = 1; - private static final int MSG_TASK_UPDATE = 2; - private static final int MSG_TASK_START = 3; - private static final int MSG_DO_SHARE = 4; - - public static final int EXECUTION_RESULT_SUCCESS = 1; - public static final int EXECUTION_RESULT_FAIL = 2; - public static final int EXECUTION_RESULT_CANCEL = 3; - - private ProgressDialog mDialog; - private Future<?> mTask; - // wait the operation to finish when we want to stop it. - private boolean mWaitOnStop; - private boolean mPaused; - - private final AbstractGalleryActivity mActivity; - private final SelectionManager mSelectionManager; - private final Handler mHandler; - - private static ProgressDialog createProgressDialog( - Context context, int titleId, int progressMax) { - ProgressDialog dialog = new ProgressDialog(context); - dialog.setTitle(titleId); - dialog.setMax(progressMax); - dialog.setCancelable(false); - dialog.setIndeterminate(false); - if (progressMax > 1) { - dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); - } - return dialog; - } - - public interface ProgressListener { - public void onConfirmDialogShown(); - public void onConfirmDialogDismissed(boolean confirmed); - public void onProgressStart(); - public void onProgressUpdate(int index); - public void onProgressComplete(int result); - } - - public MenuExecutor( - AbstractGalleryActivity activity, SelectionManager selectionManager) { - mActivity = Utils.checkNotNull(activity); - mSelectionManager = Utils.checkNotNull(selectionManager); - mHandler = new SynchronizedHandler(mActivity.getGLRoot()) { - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_TASK_START: { - if (message.obj != null) { - ProgressListener listener = (ProgressListener) message.obj; - listener.onProgressStart(); - } - break; - } - case MSG_TASK_COMPLETE: { - stopTaskAndDismissDialog(); - if (message.obj != null) { - ProgressListener listener = (ProgressListener) message.obj; - listener.onProgressComplete(message.arg1); - } - mSelectionManager.leaveSelectionMode(); - break; - } - case MSG_TASK_UPDATE: { - if (mDialog != null && !mPaused) mDialog.setProgress(message.arg1); - if (message.obj != null) { - ProgressListener listener = (ProgressListener) message.obj; - listener.onProgressUpdate(message.arg1); - } - break; - } - case MSG_DO_SHARE: { - ((Activity) mActivity).startActivity((Intent) message.obj); - break; - } - } - } - }; - } - - private void stopTaskAndDismissDialog() { - if (mTask != null) { - if (!mWaitOnStop) mTask.cancel(); - if (mDialog != null && mDialog.isShowing()) mDialog.dismiss(); - mDialog = null; - mTask = null; - } - } - - public void resume() { - mPaused = false; - if (mDialog != null) mDialog.show(); - } - - public void pause() { - mPaused = true; - if (mDialog != null && mDialog.isShowing()) mDialog.hide(); - } - - public void destroy() { - stopTaskAndDismissDialog(); - } - - private void onProgressUpdate(int index, ProgressListener listener) { - mHandler.sendMessage( - mHandler.obtainMessage(MSG_TASK_UPDATE, index, 0, listener)); - } - - private void onProgressStart(ProgressListener listener) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_START, listener)); - } - - private void onProgressComplete(int result, ProgressListener listener) { - mHandler.sendMessage(mHandler.obtainMessage(MSG_TASK_COMPLETE, result, 0, listener)); - } - - public static void updateMenuOperation(Menu menu, int supported) { - boolean supportDelete = (supported & MediaObject.SUPPORT_DELETE) != 0; - boolean supportRotate = (supported & MediaObject.SUPPORT_ROTATE) != 0; - boolean supportCrop = (supported & MediaObject.SUPPORT_CROP) != 0; - boolean supportTrim = (supported & MediaObject.SUPPORT_TRIM) != 0; - boolean supportMute = (supported & MediaObject.SUPPORT_MUTE) != 0; - boolean supportShare = (supported & MediaObject.SUPPORT_SHARE) != 0; - boolean supportSetAs = (supported & MediaObject.SUPPORT_SETAS) != 0; - boolean supportShowOnMap = (supported & MediaObject.SUPPORT_SHOW_ON_MAP) != 0; - boolean supportCache = (supported & MediaObject.SUPPORT_CACHE) != 0; - boolean supportEdit = (supported & MediaObject.SUPPORT_EDIT) != 0; - boolean supportInfo = (supported & MediaObject.SUPPORT_INFO) != 0; - - setMenuItemVisible(menu, R.id.action_delete, supportDelete); - setMenuItemVisible(menu, R.id.action_rotate_ccw, supportRotate); - setMenuItemVisible(menu, R.id.action_rotate_cw, supportRotate); - setMenuItemVisible(menu, R.id.action_crop, supportCrop); - setMenuItemVisible(menu, R.id.action_trim, supportTrim); - setMenuItemVisible(menu, R.id.action_mute, supportMute); - // Hide panorama until call to updateMenuForPanorama corrects it - setMenuItemVisible(menu, R.id.action_share_panorama, false); - setMenuItemVisible(menu, R.id.action_share, supportShare); - setMenuItemVisible(menu, R.id.action_setas, supportSetAs); - setMenuItemVisible(menu, R.id.action_show_on_map, supportShowOnMap); - setMenuItemVisible(menu, R.id.action_edit, supportEdit); - setMenuItemVisible(menu, R.id.action_simple_edit, supportEdit); - setMenuItemVisible(menu, R.id.action_details, supportInfo); - } - - public static void updateMenuForPanorama(Menu menu, boolean shareAsPanorama360, - boolean disablePanorama360Options) { - setMenuItemVisible(menu, R.id.action_share_panorama, shareAsPanorama360); - if (disablePanorama360Options) { - setMenuItemVisible(menu, R.id.action_rotate_ccw, false); - setMenuItemVisible(menu, R.id.action_rotate_cw, false); - } - } - - private static void setMenuItemVisible(Menu menu, int itemId, boolean visible) { - MenuItem item = menu.findItem(itemId); - if (item != null) item.setVisible(visible); - } - - private Path getSingleSelectedPath() { - ArrayList<Path> ids = mSelectionManager.getSelected(true); - Utils.assertTrue(ids.size() == 1); - return ids.get(0); - } - - private Intent getIntentBySingleSelectedPath(String action) { - DataManager manager = mActivity.getDataManager(); - Path path = getSingleSelectedPath(); - String mimeType = getMimeType(manager.getMediaType(path)); - return new Intent(action).setDataAndType(manager.getContentUri(path), mimeType); - } - - private void onMenuClicked(int action, ProgressListener listener) { - onMenuClicked(action, listener, false, true); - } - - public void onMenuClicked(int action, ProgressListener listener, - boolean waitOnStop, boolean showDialog) { - int title; - switch (action) { - case R.id.action_select_all: - if (mSelectionManager.inSelectAllMode()) { - mSelectionManager.deSelectAll(); - } else { - mSelectionManager.selectAll(); - } - return; - case R.id.action_crop: { - Intent intent = getIntentBySingleSelectedPath(CropActivity.CROP_ACTION); - ((Activity) mActivity).startActivity(intent); - return; - } - case R.id.action_edit: { - Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_EDIT) - .setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - ((Activity) mActivity).startActivity(Intent.createChooser(intent, null)); - return; - } - case R.id.action_setas: { - Intent intent = getIntentBySingleSelectedPath(Intent.ACTION_ATTACH_DATA) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); - intent.putExtra("mimeType", intent.getType()); - Activity activity = mActivity; - activity.startActivity(Intent.createChooser( - intent, activity.getString(R.string.set_as))); - return; - } - case R.id.action_delete: - title = R.string.delete; - break; - case R.id.action_rotate_cw: - title = R.string.rotate_right; - break; - case R.id.action_rotate_ccw: - title = R.string.rotate_left; - break; - case R.id.action_show_on_map: - title = R.string.show_on_map; - break; - default: - return; - } - startAction(action, title, listener, waitOnStop, showDialog); - } - - private class ConfirmDialogListener implements OnClickListener, OnCancelListener { - private final int mActionId; - private final ProgressListener mListener; - - public ConfirmDialogListener(int actionId, ProgressListener listener) { - mActionId = actionId; - mListener = listener; - } - - @Override - public void onClick(DialogInterface dialog, int which) { - if (which == DialogInterface.BUTTON_POSITIVE) { - if (mListener != null) { - mListener.onConfirmDialogDismissed(true); - } - onMenuClicked(mActionId, mListener); - } else { - if (mListener != null) { - mListener.onConfirmDialogDismissed(false); - } - } - } - - @Override - public void onCancel(DialogInterface dialog) { - if (mListener != null) { - mListener.onConfirmDialogDismissed(false); - } - } - } - - public void onMenuClicked(MenuItem menuItem, String confirmMsg, - final ProgressListener listener) { - final int action = menuItem.getItemId(); - - if (confirmMsg != null) { - if (listener != null) listener.onConfirmDialogShown(); - ConfirmDialogListener cdl = new ConfirmDialogListener(action, listener); - new AlertDialog.Builder(mActivity.getAndroidContext()) - .setMessage(confirmMsg) - .setOnCancelListener(cdl) - .setPositiveButton(R.string.ok, cdl) - .setNegativeButton(R.string.cancel, cdl) - .create().show(); - } else { - onMenuClicked(action, listener); - } - } - - public void startAction(int action, int title, ProgressListener listener) { - startAction(action, title, listener, false, true); - } - - public void startAction(int action, int title, ProgressListener listener, - boolean waitOnStop, boolean showDialog) { - ArrayList<Path> ids = mSelectionManager.getSelected(false); - stopTaskAndDismissDialog(); - - Activity activity = mActivity; - if (showDialog) { - mDialog = createProgressDialog(activity, title, ids.size()); - mDialog.show(); - } else { - mDialog = null; - } - MediaOperation operation = new MediaOperation(action, ids, listener); - mTask = mActivity.getBatchServiceThreadPoolIfAvailable().submit(operation, null); - mWaitOnStop = waitOnStop; - } - - public void startSingleItemAction(int action, Path targetPath) { - ArrayList<Path> ids = new ArrayList<Path>(1); - ids.add(targetPath); - mDialog = null; - MediaOperation operation = new MediaOperation(action, ids, null); - mTask = mActivity.getBatchServiceThreadPoolIfAvailable().submit(operation, null); - mWaitOnStop = false; - } - - public static String getMimeType(int type) { - switch (type) { - case MediaObject.MEDIA_TYPE_IMAGE : - return GalleryUtils.MIME_TYPE_IMAGE; - case MediaObject.MEDIA_TYPE_VIDEO : - return GalleryUtils.MIME_TYPE_VIDEO; - default: return GalleryUtils.MIME_TYPE_ALL; - } - } - - private boolean execute( - DataManager manager, JobContext jc, int cmd, Path path) { - boolean result = true; - Log.v(TAG, "Execute cmd: " + cmd + " for " + path); - long startTime = System.currentTimeMillis(); - - switch (cmd) { - case R.id.action_delete: - manager.delete(path); - break; - case R.id.action_rotate_cw: - manager.rotate(path, 90); - break; - case R.id.action_rotate_ccw: - manager.rotate(path, -90); - break; - case R.id.action_toggle_full_caching: { - MediaObject obj = manager.getMediaObject(path); - int cacheFlag = obj.getCacheFlag(); - if (cacheFlag == MediaObject.CACHE_FLAG_FULL) { - cacheFlag = MediaObject.CACHE_FLAG_SCREENNAIL; - } else { - cacheFlag = MediaObject.CACHE_FLAG_FULL; - } - obj.cache(cacheFlag); - break; - } - case R.id.action_show_on_map: { - MediaItem item = (MediaItem) manager.getMediaObject(path); - double latlng[] = new double[2]; - item.getLatLong(latlng); - if (GalleryUtils.isValidLocation(latlng[0], latlng[1])) { - GalleryUtils.showOnMap(mActivity, latlng[0], latlng[1]); - } - break; - } - default: - throw new AssertionError(); - } - Log.v(TAG, "It takes " + (System.currentTimeMillis() - startTime) + - " ms to execute cmd for " + path); - return result; - } - - private class MediaOperation implements Job<Void> { - private final ArrayList<Path> mItems; - private final int mOperation; - private final ProgressListener mListener; - - public MediaOperation(int operation, ArrayList<Path> items, - ProgressListener listener) { - mOperation = operation; - mItems = items; - mListener = listener; - } - - @Override - public Void run(JobContext jc) { - int index = 0; - DataManager manager = mActivity.getDataManager(); - int result = EXECUTION_RESULT_SUCCESS; - try { - onProgressStart(mListener); - for (Path id : mItems) { - if (jc.isCancelled()) { - result = EXECUTION_RESULT_CANCEL; - break; - } - if (!execute(manager, jc, mOperation, id)) { - result = EXECUTION_RESULT_FAIL; - } - onProgressUpdate(index++, mListener); - } - } catch (Throwable th) { - Log.e(TAG, "failed to execute operation " + mOperation - + " : " + th); - } finally { - onProgressComplete(result, mListener); - } - return null; - } - } -} diff --git a/src/com/android/gallery3d/ui/OrientationSource.java b/src/com/android/gallery3d/ui/OrientationSource.java deleted file mode 100644 index e13ce1cec..000000000 --- a/src/com/android/gallery3d/ui/OrientationSource.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -public interface OrientationSource { - public int getDisplayRotation(); - public int getCompensation(); -} diff --git a/src/com/android/gallery3d/ui/Paper.java b/src/com/android/gallery3d/ui/Paper.java deleted file mode 100644 index b36f5c3a2..000000000 --- a/src/com/android/gallery3d/ui/Paper.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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.ui; - -import android.graphics.Rect; -import android.opengl.Matrix; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; - -import com.android.gallery3d.common.Utils; - -// This class does the overscroll effect. -class Paper { - @SuppressWarnings("unused") - private static final String TAG = "Paper"; - private static final int ROTATE_FACTOR = 4; - private EdgeAnimation mAnimationLeft = new EdgeAnimation(); - private EdgeAnimation mAnimationRight = new EdgeAnimation(); - private int mWidth; - private float[] mMatrix = new float[16]; - - public void overScroll(float distance) { - distance /= mWidth; // make it relative to width - if (distance < 0) { - mAnimationLeft.onPull(-distance); - } else { - mAnimationRight.onPull(distance); - } - } - - public void edgeReached(float velocity) { - velocity /= mWidth; // make it relative to width - if (velocity < 0) { - mAnimationRight.onAbsorb(-velocity); - } else { - mAnimationLeft.onAbsorb(velocity); - } - } - - public void onRelease() { - mAnimationLeft.onRelease(); - mAnimationRight.onRelease(); - } - - public boolean advanceAnimation() { - // Note that we use "|" because we want both animations get updated. - return mAnimationLeft.update() | mAnimationRight.update(); - } - - public void setSize(int width, int height) { - mWidth = width; - } - - public float[] getTransform(Rect rect, float scrollX) { - float left = mAnimationLeft.getValue(); - float right = mAnimationRight.getValue(); - float screenX = rect.centerX() - scrollX; - // We linearly interpolate the value [left, right] for the screenX - // range int [-1/4, 5/4]*mWidth. So if part of the thumbnail is outside - // the screen, we still get some transform. - float x = screenX + mWidth / 4; - int range = 3 * mWidth / 2; - float t = ((range - x) * left - x * right) / range; - // compress t to the range (-1, 1) by the function - // f(t) = (1 / (1 + e^-t) - 0.5) * 2 - // then multiply by 90 to make the range (-45, 45) - float degrees = - (1 / (1 + (float) Math.exp(-t * ROTATE_FACTOR)) - 0.5f) * 2 * -45; - Matrix.setIdentityM(mMatrix, 0); - Matrix.translateM(mMatrix, 0, mMatrix, 0, rect.centerX(), rect.centerY(), 0); - Matrix.rotateM(mMatrix, 0, degrees, 0, 1, 0); - Matrix.translateM(mMatrix, 0, mMatrix, 0, -rect.width() / 2, -rect.height() / 2, 0); - return mMatrix; - } -} - -// This class follows the structure of frameworks's EdgeEffect class. -class EdgeAnimation { - @SuppressWarnings("unused") - private static final String TAG = "EdgeAnimation"; - - private static final int STATE_IDLE = 0; - private static final int STATE_PULL = 1; - private static final int STATE_ABSORB = 2; - private static final int STATE_RELEASE = 3; - - // Time it will take the effect to fully done in ms - private static final int ABSORB_TIME = 200; - private static final int RELEASE_TIME = 500; - - private static final float VELOCITY_FACTOR = 0.1f; - - private final Interpolator mInterpolator; - - private int mState; - private float mValue; - - private float mValueStart; - private float mValueFinish; - private long mStartTime; - private long mDuration; - - public EdgeAnimation() { - mInterpolator = new DecelerateInterpolator(); - mState = STATE_IDLE; - } - - private void startAnimation(float start, float finish, long duration, - int newState) { - mValueStart = start; - mValueFinish = finish; - mDuration = duration; - mStartTime = now(); - mState = newState; - } - - // The deltaDistance's magnitude is in the range of -1 (no change) to 1. - // The value 1 is the full length of the view. Negative values means the - // movement is in the opposite direction. - public void onPull(float deltaDistance) { - if (mState == STATE_ABSORB) return; - mValue = Utils.clamp(mValue + deltaDistance, -1.0f, 1.0f); - mState = STATE_PULL; - } - - public void onRelease() { - if (mState == STATE_IDLE || mState == STATE_ABSORB) return; - startAnimation(mValue, 0, RELEASE_TIME, STATE_RELEASE); - } - - public void onAbsorb(float velocity) { - float finish = Utils.clamp(mValue + velocity * VELOCITY_FACTOR, - -1.0f, 1.0f); - startAnimation(mValue, finish, ABSORB_TIME, STATE_ABSORB); - } - - public boolean update() { - if (mState == STATE_IDLE) return false; - if (mState == STATE_PULL) return true; - - float t = Utils.clamp((float)(now() - mStartTime) / mDuration, 0.0f, 1.0f); - /* Use linear interpolation for absorb, quadratic for others */ - float interp = (mState == STATE_ABSORB) - ? t : mInterpolator.getInterpolation(t); - - mValue = mValueStart + (mValueFinish - mValueStart) * interp; - - if (t >= 1.0f) { - switch (mState) { - case STATE_ABSORB: - startAnimation(mValue, 0, RELEASE_TIME, STATE_RELEASE); - break; - case STATE_RELEASE: - mState = STATE_IDLE; - break; - } - } - - return true; - } - - public float getValue() { - return mValue; - } - - private long now() { - return AnimationTime.get(); - } -} diff --git a/src/com/android/gallery3d/ui/PhotoFallbackEffect.java b/src/com/android/gallery3d/ui/PhotoFallbackEffect.java deleted file mode 100644 index 4603285a4..000000000 --- a/src/com/android/gallery3d/ui/PhotoFallbackEffect.java +++ /dev/null @@ -1,179 +0,0 @@ -/* - * 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.ui; - -import android.graphics.Rect; -import android.graphics.RectF; -import android.view.animation.DecelerateInterpolator; -import android.view.animation.Interpolator; - -import com.android.gallery3d.anim.Animation; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.RawTexture; -import com.android.gallery3d.ui.AlbumSlotRenderer.SlotFilter; - -import java.util.ArrayList; - -public class PhotoFallbackEffect extends Animation implements SlotFilter { - - private static final int ANIM_DURATION = 300; - private static final Interpolator ANIM_INTERPOLATE = new DecelerateInterpolator(1.5f); - - public static class Entry { - public int index; - public Path path; - public Rect source; - public Rect dest; - public RawTexture texture; - - public Entry(Path path, Rect source, RawTexture texture) { - this.path = path; - this.source = source; - this.texture = texture; - } - } - - public interface PositionProvider { - public Rect getPosition(int index); - public int getItemIndex(Path path); - } - - private RectF mSource = new RectF(); - private RectF mTarget = new RectF(); - private float mProgress; - private PositionProvider mPositionProvider; - - private ArrayList<Entry> mList = new ArrayList<Entry>(); - - public PhotoFallbackEffect() { - setDuration(ANIM_DURATION); - setInterpolator(ANIM_INTERPOLATE); - } - - public void addEntry(Path path, Rect rect, RawTexture texture) { - mList.add(new Entry(path, rect, texture)); - } - - public Entry getEntry(Path path) { - for (int i = 0, n = mList.size(); i < n; ++i) { - Entry entry = mList.get(i); - if (entry.path == path) return entry; - } - return null; - } - - public boolean draw(GLCanvas canvas) { - boolean more = calculate(AnimationTime.get()); - for (int i = 0, n = mList.size(); i < n; ++i) { - Entry entry = mList.get(i); - if (entry.index < 0) continue; - entry.dest = mPositionProvider.getPosition(entry.index); - drawEntry(canvas, entry); - } - return more; - } - - private void drawEntry(GLCanvas canvas, Entry entry) { - if (!entry.texture.isLoaded()) return; - - int w = entry.texture.getWidth(); - int h = entry.texture.getHeight(); - - Rect s = entry.source; - Rect d = entry.dest; - - // the following calculation is based on d.width() == d.height() - - float p = mProgress; - - float fullScale = (float) d.height() / Math.min(s.width(), s.height()); - float scale = fullScale * p + 1 * (1 - p); - - float cx = d.centerX() * p + s.centerX() * (1 - p); - float cy = d.centerY() * p + s.centerY() * (1 - p); - - float ch = s.height() * scale; - float cw = s.width() * scale; - - if (w > h) { - // draw the center part - mTarget.set(cx - ch / 2, cy - ch / 2, cx + ch / 2, cy + ch / 2); - mSource.set((w - h) / 2, 0, (w + h) / 2, h); - canvas.drawTexture(entry.texture, mSource, mTarget); - - canvas.save(GLCanvas.SAVE_FLAG_ALPHA); - canvas.multiplyAlpha(1 - p); - - // draw the left part - mTarget.set(cx - cw / 2, cy - ch / 2, cx - ch / 2, cy + ch / 2); - mSource.set(0, 0, (w - h) / 2, h); - canvas.drawTexture(entry.texture, mSource, mTarget); - - // draw the right part - mTarget.set(cx + ch / 2, cy - ch / 2, cx + cw / 2, cy + ch / 2); - mSource.set((w + h) / 2, 0, w, h); - canvas.drawTexture(entry.texture, mSource, mTarget); - - canvas.restore(); - } else { - // draw the center part - mTarget.set(cx - cw / 2, cy - cw / 2, cx + cw / 2, cy + cw / 2); - mSource.set(0, (h - w) / 2, w, (h + w) / 2); - canvas.drawTexture(entry.texture, mSource, mTarget); - - canvas.save(GLCanvas.SAVE_FLAG_ALPHA); - canvas.multiplyAlpha(1 - p); - - // draw the upper part - mTarget.set(cx - cw / 2, cy - ch / 2, cx + cw / 2, cy - cw / 2); - mSource.set(0, 0, w, (h - w) / 2); - canvas.drawTexture(entry.texture, mSource, mTarget); - - // draw the bottom part - mTarget.set(cx - cw / 2, cy + cw / 2, cx + cw / 2, cy + ch / 2); - mSource.set(0, (w + h) / 2, w, h); - canvas.drawTexture(entry.texture, mSource, mTarget); - - canvas.restore(); - } - } - - @Override - protected void onCalculate(float progress) { - mProgress = progress; - } - - public void setPositionProvider(PositionProvider provider) { - mPositionProvider = provider; - if (mPositionProvider != null) { - for (int i = 0, n = mList.size(); i < n; ++i) { - Entry entry = mList.get(i); - entry.index = mPositionProvider.getItemIndex(entry.path); - } - } - } - - @Override - public boolean acceptSlot(int index) { - for (int i = 0, n = mList.size(); i < n; ++i) { - Entry entry = mList.get(i); - if (entry.index == index) return false; - } - return true; - } -} diff --git a/src/com/android/gallery3d/ui/PhotoView.java b/src/com/android/gallery3d/ui/PhotoView.java deleted file mode 100644 index 7afa20348..000000000 --- a/src/com/android/gallery3d/ui/PhotoView.java +++ /dev/null @@ -1,1858 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.content.res.Configuration; -import android.graphics.Color; -import android.graphics.Matrix; -import android.graphics.Rect; -import android.os.Build; -import android.os.Message; -import android.util.FloatMath; -import android.view.MotionEvent; -import android.view.View.MeasureSpec; -import android.view.animation.AccelerateInterpolator; - -import com.android.gallery3d.R; -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaObject; -import com.android.gallery3d.data.Path; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.RawTexture; -import com.android.gallery3d.glrenderer.ResourceTexture; -import com.android.gallery3d.glrenderer.StringTexture; -import com.android.gallery3d.glrenderer.Texture; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.RangeArray; -import com.android.gallery3d.util.UsageStatistics; - -public class PhotoView extends GLView { - @SuppressWarnings("unused") - private static final String TAG = "PhotoView"; - private final int mPlaceholderColor; - - public static final int INVALID_SIZE = -1; - public static final long INVALID_DATA_VERSION = - MediaObject.INVALID_DATA_VERSION; - - public static class Size { - public int width; - public int height; - } - - public interface Model extends TileImageView.TileSource { - public int getCurrentIndex(); - public void moveTo(int index); - - // Returns the size for the specified picture. If the size information is - // not avaiable, width = height = 0. - public void getImageSize(int offset, Size size); - - // Returns the media item for the specified picture. - public MediaItem getMediaItem(int offset); - - // Returns the rotation for the specified picture. - public int getImageRotation(int offset); - - // This amends the getScreenNail() method of TileImageView.Model to get - // ScreenNail at previous (negative offset) or next (positive offset) - // positions. Returns null if the specified ScreenNail is unavailable. - public ScreenNail getScreenNail(int offset); - - // Set this to true if we need the model to provide full images. - public void setNeedFullImage(boolean enabled); - - // Returns true if the item is the Camera preview. - public boolean isCamera(int offset); - - // Returns true if the item is the Panorama. - public boolean isPanorama(int offset); - - // Returns true if the item is a static image that represents camera - // preview. - public boolean isStaticCamera(int offset); - - // Returns true if the item is a Video. - public boolean isVideo(int offset); - - // Returns true if the item can be deleted. - public boolean isDeletable(int offset); - - public static final int LOADING_INIT = 0; - public static final int LOADING_COMPLETE = 1; - public static final int LOADING_FAIL = 2; - - public int getLoadingState(int offset); - - // When data change happens, we need to decide which MediaItem to focus - // on. - // - // 1. If focus hint path != null, we try to focus on it if we can find - // it. This is used for undo a deletion, so we can focus on the - // undeleted item. - // - // 2. Otherwise try to focus on the MediaItem that is currently focused, - // if we can find it. - // - // 3. Otherwise try to focus on the previous MediaItem or the next - // MediaItem, depending on the value of focus hint direction. - public static final int FOCUS_HINT_NEXT = 0; - public static final int FOCUS_HINT_PREVIOUS = 1; - public void setFocusHintDirection(int direction); - public void setFocusHintPath(Path path); - } - - public interface Listener { - public void onSingleTapUp(int x, int y); - public void onFullScreenChanged(boolean full); - public void onActionBarAllowed(boolean allowed); - public void onActionBarWanted(); - public void onCurrentImageUpdated(); - public void onDeleteImage(Path path, int offset); - public void onUndoDeleteImage(); - public void onCommitDeleteImage(); - public void onFilmModeChanged(boolean enabled); - public void onPictureCenter(boolean isCamera); - public void onUndoBarVisibilityChanged(boolean visible); - } - - // The rules about orientation locking: - // - // (1) We need to lock the orientation if we are in page mode camera - // preview, so there is no (unwanted) rotation animation when the user - // rotates the device. - // - // (2) We need to unlock the orientation if we want to show the action bar - // because the action bar follows the system orientation. - // - // The rules about action bar: - // - // (1) If we are in film mode, we don't show action bar. - // - // (2) If we go from camera to gallery with capture animation, we show - // action bar. - private static final int MSG_CANCEL_EXTRA_SCALING = 2; - private static final int MSG_SWITCH_FOCUS = 3; - private static final int MSG_CAPTURE_ANIMATION_DONE = 4; - private static final int MSG_DELETE_ANIMATION_DONE = 5; - private static final int MSG_DELETE_DONE = 6; - private static final int MSG_UNDO_BAR_TIMEOUT = 7; - private static final int MSG_UNDO_BAR_FULL_CAMERA = 8; - - private static final float SWIPE_THRESHOLD = 300f; - - private static final float DEFAULT_TEXT_SIZE = 20; - private static float TRANSITION_SCALE_FACTOR = 0.74f; - private static final int ICON_RATIO = 6; - - // whether we want to apply card deck effect in page mode. - private static final boolean CARD_EFFECT = true; - - // whether we want to apply offset effect in film mode. - private static final boolean OFFSET_EFFECT = true; - - // Used to calculate the scaling factor for the card deck effect. - private ZInterpolator mScaleInterpolator = new ZInterpolator(0.5f); - - // Used to calculate the alpha factor for the fading animation. - private AccelerateInterpolator mAlphaInterpolator = - new AccelerateInterpolator(0.9f); - - // We keep this many previous ScreenNails. (also this many next ScreenNails) - public static final int SCREEN_NAIL_MAX = 3; - - // These are constants for the delete gesture. - private static final int SWIPE_ESCAPE_VELOCITY = 500; // dp/sec - private static final int MAX_DISMISS_VELOCITY = 2500; // dp/sec - private static final int SWIPE_ESCAPE_DISTANCE = 150; // dp - - // The picture entries, the valid index is from -SCREEN_NAIL_MAX to - // SCREEN_NAIL_MAX. - private final RangeArray<Picture> mPictures = - new RangeArray<Picture>(-SCREEN_NAIL_MAX, SCREEN_NAIL_MAX); - private Size[] mSizes = new Size[2 * SCREEN_NAIL_MAX + 1]; - - private final MyGestureListener mGestureListener; - private final GestureRecognizer mGestureRecognizer; - private final PositionController mPositionController; - - private Listener mListener; - private Model mModel; - private StringTexture mNoThumbnailText; - private TileImageView mTileView; - private EdgeView mEdgeView; - private UndoBarView mUndoBar; - private Texture mVideoPlayIcon; - - private SynchronizedHandler mHandler; - - private boolean mCancelExtraScalingPending; - private boolean mFilmMode = false; - private boolean mWantPictureCenterCallbacks = false; - private int mDisplayRotation = 0; - private int mCompensation = 0; - private boolean mFullScreenCamera; - private Rect mCameraRelativeFrame = new Rect(); - private Rect mCameraRect = new Rect(); - private boolean mFirst = true; - - // [mPrevBound, mNextBound] is the range of index for all pictures in the - // model, if we assume the index of current focused picture is 0. So if - // there are some previous pictures, mPrevBound < 0, and if there are some - // next pictures, mNextBound > 0. - private int mPrevBound; - private int mNextBound; - - // This variable prevents us doing snapback until its values goes to 0. This - // happens if the user gesture is still in progress or we are in a capture - // animation. - private int mHolding; - private static final int HOLD_TOUCH_DOWN = 1; - private static final int HOLD_CAPTURE_ANIMATION = 2; - private static final int HOLD_DELETE = 4; - - // mTouchBoxIndex is the index of the box that is touched by the down - // gesture in film mode. The value Integer.MAX_VALUE means no box was - // touched. - private int mTouchBoxIndex = Integer.MAX_VALUE; - // Whether the box indicated by mTouchBoxIndex is deletable. Only meaningful - // if mTouchBoxIndex is not Integer.MAX_VALUE. - private boolean mTouchBoxDeletable; - // This is the index of the last deleted item. This is only used as a hint - // to hide the undo button when we are too far away from the deleted - // item. The value Integer.MAX_VALUE means there is no such hint. - private int mUndoIndexHint = Integer.MAX_VALUE; - - private Context mContext; - - public PhotoView(AbstractGalleryActivity activity) { - mTileView = new TileImageView(activity); - addComponent(mTileView); - mContext = activity.getAndroidContext(); - mPlaceholderColor = mContext.getResources().getColor( - R.color.photo_placeholder); - mEdgeView = new EdgeView(mContext); - addComponent(mEdgeView); - mUndoBar = new UndoBarView(mContext); - addComponent(mUndoBar); - mUndoBar.setVisibility(GLView.INVISIBLE); - mUndoBar.setOnClickListener(new OnClickListener() { - @Override - public void onClick(GLView v) { - mListener.onUndoDeleteImage(); - hideUndoBar(); - } - }); - mNoThumbnailText = StringTexture.newInstance( - mContext.getString(R.string.no_thumbnail), - DEFAULT_TEXT_SIZE, Color.WHITE); - - mHandler = new MyHandler(activity.getGLRoot()); - - mGestureListener = new MyGestureListener(); - mGestureRecognizer = new GestureRecognizer(mContext, mGestureListener); - - mPositionController = new PositionController(mContext, - new PositionController.Listener() { - - @Override - public void invalidate() { - PhotoView.this.invalidate(); - } - - @Override - public boolean isHoldingDown() { - return (mHolding & HOLD_TOUCH_DOWN) != 0; - } - - @Override - public boolean isHoldingDelete() { - return (mHolding & HOLD_DELETE) != 0; - } - - @Override - public void onPull(int offset, int direction) { - mEdgeView.onPull(offset, direction); - } - - @Override - public void onRelease() { - mEdgeView.onRelease(); - } - - @Override - public void onAbsorb(int velocity, int direction) { - mEdgeView.onAbsorb(velocity, direction); - } - }); - mVideoPlayIcon = new ResourceTexture(mContext, R.drawable.ic_control_play); - for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { - if (i == 0) { - mPictures.put(i, new FullPicture()); - } else { - mPictures.put(i, new ScreenNailPicture(i)); - } - } - } - - public void stopScrolling() { - mPositionController.stopScrolling(); - } - - public void setModel(Model model) { - mModel = model; - mTileView.setModel(mModel); - } - - class MyHandler extends SynchronizedHandler { - public MyHandler(GLRoot root) { - super(root); - } - - @Override - public void handleMessage(Message message) { - switch (message.what) { - case MSG_CANCEL_EXTRA_SCALING: { - mGestureRecognizer.cancelScale(); - mPositionController.setExtraScalingRange(false); - mCancelExtraScalingPending = false; - break; - } - case MSG_SWITCH_FOCUS: { - switchFocus(); - break; - } - case MSG_CAPTURE_ANIMATION_DONE: { - // message.arg1 is the offset parameter passed to - // switchWithCaptureAnimation(). - captureAnimationDone(message.arg1); - break; - } - case MSG_DELETE_ANIMATION_DONE: { - // message.obj is the Path of the MediaItem which should be - // deleted. message.arg1 is the offset of the image. - mListener.onDeleteImage((Path) message.obj, message.arg1); - // Normally a box which finishes delete animation will hold - // position until the underlying MediaItem is actually - // deleted, and HOLD_DELETE will be cancelled that time. In - // case the MediaItem didn't actually get deleted in 2 - // seconds, we will cancel HOLD_DELETE and make it bounce - // back. - - // We make sure there is at most one MSG_DELETE_DONE - // in the handler. - mHandler.removeMessages(MSG_DELETE_DONE); - Message m = mHandler.obtainMessage(MSG_DELETE_DONE); - mHandler.sendMessageDelayed(m, 2000); - - int numberOfPictures = mNextBound - mPrevBound + 1; - if (numberOfPictures == 2) { - if (mModel.isCamera(mNextBound) - || mModel.isCamera(mPrevBound)) { - numberOfPictures--; - } - } - showUndoBar(numberOfPictures <= 1); - break; - } - case MSG_DELETE_DONE: { - if (!mHandler.hasMessages(MSG_DELETE_ANIMATION_DONE)) { - mHolding &= ~HOLD_DELETE; - snapback(); - } - break; - } - case MSG_UNDO_BAR_TIMEOUT: { - checkHideUndoBar(UNDO_BAR_TIMEOUT); - break; - } - case MSG_UNDO_BAR_FULL_CAMERA: { - checkHideUndoBar(UNDO_BAR_FULL_CAMERA); - break; - } - default: throw new AssertionError(message.what); - } - } - } - - public void setWantPictureCenterCallbacks(boolean wanted) { - mWantPictureCenterCallbacks = wanted; - } - - //////////////////////////////////////////////////////////////////////////// - // Data/Image change notifications - //////////////////////////////////////////////////////////////////////////// - - public void notifyDataChange(int[] fromIndex, int prevBound, int nextBound) { - mPrevBound = prevBound; - mNextBound = nextBound; - - // Update mTouchBoxIndex - if (mTouchBoxIndex != Integer.MAX_VALUE) { - int k = mTouchBoxIndex; - mTouchBoxIndex = Integer.MAX_VALUE; - for (int i = 0; i < 2 * SCREEN_NAIL_MAX + 1; i++) { - if (fromIndex[i] == k) { - mTouchBoxIndex = i - SCREEN_NAIL_MAX; - break; - } - } - } - - // Hide undo button if we are too far away - if (mUndoIndexHint != Integer.MAX_VALUE) { - if (Math.abs(mUndoIndexHint - mModel.getCurrentIndex()) >= 3) { - hideUndoBar(); - } - } - - // Update the ScreenNails. - for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { - Picture p = mPictures.get(i); - p.reload(); - mSizes[i + SCREEN_NAIL_MAX] = p.getSize(); - } - - boolean wasDeleting = mPositionController.hasDeletingBox(); - - // Move the boxes - mPositionController.moveBox(fromIndex, mPrevBound < 0, mNextBound > 0, - mModel.isCamera(0), mSizes); - - for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { - setPictureSize(i); - } - - boolean isDeleting = mPositionController.hasDeletingBox(); - - // If the deletion is done, make HOLD_DELETE persist for only the time - // needed for a snapback animation. - if (wasDeleting && !isDeleting) { - mHandler.removeMessages(MSG_DELETE_DONE); - Message m = mHandler.obtainMessage(MSG_DELETE_DONE); - mHandler.sendMessageDelayed( - m, PositionController.SNAPBACK_ANIMATION_TIME); - } - - invalidate(); - } - - public boolean isDeleting() { - return (mHolding & HOLD_DELETE) != 0 - && mPositionController.hasDeletingBox(); - } - - public void notifyImageChange(int index) { - if (index == 0) { - mListener.onCurrentImageUpdated(); - } - mPictures.get(index).reload(); - setPictureSize(index); - invalidate(); - } - - private void setPictureSize(int index) { - Picture p = mPictures.get(index); - mPositionController.setImageSize(index, p.getSize(), - index == 0 && p.isCamera() ? mCameraRect : null); - } - - @Override - protected void onLayout( - boolean changeSize, int left, int top, int right, int bottom) { - int w = right - left; - int h = bottom - top; - mTileView.layout(0, 0, w, h); - mEdgeView.layout(0, 0, w, h); - mUndoBar.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); - mUndoBar.layout(0, h - mUndoBar.getMeasuredHeight(), w, h); - - GLRoot root = getGLRoot(); - int displayRotation = root.getDisplayRotation(); - int compensation = root.getCompensation(); - if (mDisplayRotation != displayRotation - || mCompensation != compensation) { - mDisplayRotation = displayRotation; - mCompensation = compensation; - - // We need to change the size and rotation of the Camera ScreenNail, - // but we don't want it to animate because the size doen't actually - // change in the eye of the user. - for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { - Picture p = mPictures.get(i); - if (p.isCamera()) { - p.forceSize(); - } - } - } - - updateCameraRect(); - mPositionController.setConstrainedFrame(mCameraRect); - if (changeSize) { - mPositionController.setViewSize(getWidth(), getHeight()); - } - } - - // Update the camera rectangle due to layout change or camera relative frame - // change. - private void updateCameraRect() { - // Get the width and height in framework orientation because the given - // mCameraRelativeFrame is in that coordinates. - int w = getWidth(); - int h = getHeight(); - if (mCompensation % 180 != 0) { - int tmp = w; - w = h; - h = tmp; - } - int l = mCameraRelativeFrame.left; - int t = mCameraRelativeFrame.top; - int r = mCameraRelativeFrame.right; - int b = mCameraRelativeFrame.bottom; - - // Now convert it to the coordinates we are using. - switch (mCompensation) { - case 0: mCameraRect.set(l, t, r, b); break; - case 90: mCameraRect.set(h - b, l, h - t, r); break; - case 180: mCameraRect.set(w - r, h - b, w - l, h - t); break; - case 270: mCameraRect.set(t, w - r, b, w - l); break; - } - - Log.d(TAG, "compensation = " + mCompensation - + ", CameraRelativeFrame = " + mCameraRelativeFrame - + ", mCameraRect = " + mCameraRect); - } - - public void setCameraRelativeFrame(Rect frame) { - mCameraRelativeFrame.set(frame); - updateCameraRect(); - // Originally we do - // mPositionController.setConstrainedFrame(mCameraRect); - // here, but it is moved to a parameter of the setImageSize() call, so - // it can be updated atomically with the CameraScreenNail's size change. - } - - // Returns the rotation we need to do to the camera texture before drawing - // it to the canvas, assuming the camera texture is correct when the device - // is in its natural orientation. - private int getCameraRotation() { - return (mCompensation - mDisplayRotation + 360) % 360; - } - - private int getPanoramaRotation() { - // This function is magic - // The issue here is that Pano makes bad assumptions about rotation and - // orientation. The first is it assumes only two rotations are possible, - // 0 and 90. Thus, if display rotation is >= 180, we invert the output. - // The second is that it assumes landscape is a 90 rotation from portrait, - // however on landscape devices this is not true. Thus, if we are in portrait - // on a landscape device, we need to invert the output - int orientation = mContext.getResources().getConfiguration().orientation; - boolean invertPortrait = (orientation == Configuration.ORIENTATION_PORTRAIT - && (mDisplayRotation == 90 || mDisplayRotation == 270)); - boolean invert = (mDisplayRotation >= 180); - if (invert != invertPortrait) { - return (mCompensation + 180) % 360; - } - return mCompensation; - } - - //////////////////////////////////////////////////////////////////////////// - // Pictures - //////////////////////////////////////////////////////////////////////////// - - private interface Picture { - void reload(); - void draw(GLCanvas canvas, Rect r); - void setScreenNail(ScreenNail s); - boolean isCamera(); // whether the picture is a camera preview - boolean isDeletable(); // whether the picture can be deleted - void forceSize(); // called when mCompensation changes - Size getSize(); - } - - class FullPicture implements Picture { - private int mRotation; - private boolean mIsCamera; - private boolean mIsPanorama; - private boolean mIsStaticCamera; - private boolean mIsVideo; - private boolean mIsDeletable; - private int mLoadingState = Model.LOADING_INIT; - private Size mSize = new Size(); - - @Override - public void reload() { - // mImageWidth and mImageHeight will get updated - mTileView.notifyModelInvalidated(); - - mIsCamera = mModel.isCamera(0); - mIsPanorama = mModel.isPanorama(0); - mIsStaticCamera = mModel.isStaticCamera(0); - mIsVideo = mModel.isVideo(0); - mIsDeletable = mModel.isDeletable(0); - mLoadingState = mModel.getLoadingState(0); - setScreenNail(mModel.getScreenNail(0)); - updateSize(); - } - - @Override - public Size getSize() { - return mSize; - } - - @Override - public void forceSize() { - updateSize(); - mPositionController.forceImageSize(0, mSize); - } - - private void updateSize() { - if (mIsPanorama) { - mRotation = getPanoramaRotation(); - } else if (mIsCamera && !mIsStaticCamera) { - mRotation = getCameraRotation(); - } else { - mRotation = mModel.getImageRotation(0); - } - - int w = mTileView.mImageWidth; - int h = mTileView.mImageHeight; - mSize.width = getRotated(mRotation, w, h); - mSize.height = getRotated(mRotation, h, w); - } - - @Override - public void draw(GLCanvas canvas, Rect r) { - drawTileView(canvas, r); - - // We want to have the following transitions: - // (1) Move camera preview out of its place: switch to film mode - // (2) Move camera preview into its place: switch to page mode - // The extra mWasCenter check makes sure (1) does not apply if in - // page mode, we move _to_ the camera preview from another picture. - - // Holdings except touch-down prevent the transitions. - if ((mHolding & ~HOLD_TOUCH_DOWN) != 0) return; - - if (mWantPictureCenterCallbacks && mPositionController.isCenter()) { - mListener.onPictureCenter(mIsCamera); - } - } - - @Override - public void setScreenNail(ScreenNail s) { - mTileView.setScreenNail(s); - } - - @Override - public boolean isCamera() { - return mIsCamera; - } - - @Override - public boolean isDeletable() { - return mIsDeletable; - } - - private void drawTileView(GLCanvas canvas, Rect r) { - float imageScale = mPositionController.getImageScale(); - int viewW = getWidth(); - int viewH = getHeight(); - float cx = r.exactCenterX(); - float cy = r.exactCenterY(); - float scale = 1f; // the scaling factor due to card effect - - canvas.save(GLCanvas.SAVE_FLAG_MATRIX | GLCanvas.SAVE_FLAG_ALPHA); - float filmRatio = mPositionController.getFilmRatio(); - boolean wantsCardEffect = CARD_EFFECT && !mIsCamera - && filmRatio != 1f && !mPictures.get(-1).isCamera() - && !mPositionController.inOpeningAnimation(); - boolean wantsOffsetEffect = OFFSET_EFFECT && mIsDeletable - && filmRatio == 1f && r.centerY() != viewH / 2; - if (wantsCardEffect) { - // Calculate the move-out progress value. - int left = r.left; - int right = r.right; - float progress = calculateMoveOutProgress(left, right, viewW); - progress = Utils.clamp(progress, -1f, 1f); - - // We only want to apply the fading animation if the scrolling - // movement is to the right. - if (progress < 0) { - scale = getScrollScale(progress); - float alpha = getScrollAlpha(progress); - scale = interpolate(filmRatio, scale, 1f); - alpha = interpolate(filmRatio, alpha, 1f); - - imageScale *= scale; - canvas.multiplyAlpha(alpha); - - float cxPage; // the cx value in page mode - if (right - left <= viewW) { - // If the picture is narrower than the view, keep it at - // the center of the view. - cxPage = viewW / 2f; - } else { - // If the picture is wider than the view (it's - // zoomed-in), keep the left edge of the object align - // the the left edge of the view. - cxPage = (right - left) * scale / 2f; - } - cx = interpolate(filmRatio, cxPage, cx); - } - } else if (wantsOffsetEffect) { - float offset = (float) (r.centerY() - viewH / 2) / viewH; - float alpha = getOffsetAlpha(offset); - canvas.multiplyAlpha(alpha); - } - - // Draw the tile view. - setTileViewPosition(cx, cy, viewW, viewH, imageScale); - renderChild(canvas, mTileView); - - // Draw the play video icon and the message. - canvas.translate((int) (cx + 0.5f), (int) (cy + 0.5f)); - int s = (int) (scale * Math.min(r.width(), r.height()) + 0.5f); - if (mIsVideo) drawVideoPlayIcon(canvas, s); - if (mLoadingState == Model.LOADING_FAIL) { - drawLoadingFailMessage(canvas); - } - - // Draw a debug indicator showing which picture has focus (index == - // 0). - //canvas.fillRect(-10, -10, 20, 20, 0x80FF00FF); - - canvas.restore(); - } - - // Set the position of the tile view - private void setTileViewPosition(float cx, float cy, - int viewW, int viewH, float scale) { - // Find out the bitmap coordinates of the center of the view - int imageW = mPositionController.getImageWidth(); - int imageH = mPositionController.getImageHeight(); - int centerX = (int) (imageW / 2f + (viewW / 2f - cx) / scale + 0.5f); - int centerY = (int) (imageH / 2f + (viewH / 2f - cy) / scale + 0.5f); - - int inverseX = imageW - centerX; - int inverseY = imageH - centerY; - int x, y; - switch (mRotation) { - case 0: x = centerX; y = centerY; break; - case 90: x = centerY; y = inverseX; break; - case 180: x = inverseX; y = inverseY; break; - case 270: x = inverseY; y = centerX; break; - default: - throw new RuntimeException(String.valueOf(mRotation)); - } - mTileView.setPosition(x, y, scale, mRotation); - } - } - - private class ScreenNailPicture implements Picture { - private int mIndex; - private int mRotation; - private ScreenNail mScreenNail; - private boolean mIsCamera; - private boolean mIsPanorama; - private boolean mIsStaticCamera; - private boolean mIsVideo; - private boolean mIsDeletable; - private int mLoadingState = Model.LOADING_INIT; - private Size mSize = new Size(); - - public ScreenNailPicture(int index) { - mIndex = index; - } - - @Override - public void reload() { - mIsCamera = mModel.isCamera(mIndex); - mIsPanorama = mModel.isPanorama(mIndex); - mIsStaticCamera = mModel.isStaticCamera(mIndex); - mIsVideo = mModel.isVideo(mIndex); - mIsDeletable = mModel.isDeletable(mIndex); - mLoadingState = mModel.getLoadingState(mIndex); - setScreenNail(mModel.getScreenNail(mIndex)); - updateSize(); - } - - @Override - public Size getSize() { - return mSize; - } - - @Override - public void draw(GLCanvas canvas, Rect r) { - if (mScreenNail == null) { - // Draw a placeholder rectange if there should be a picture in - // this position (but somehow there isn't). - if (mIndex >= mPrevBound && mIndex <= mNextBound) { - drawPlaceHolder(canvas, r); - } - return; - } - int w = getWidth(); - int h = getHeight(); - if (r.left >= w || r.right <= 0 || r.top >= h || r.bottom <= 0) { - mScreenNail.noDraw(); - return; - } - - float filmRatio = mPositionController.getFilmRatio(); - boolean wantsCardEffect = CARD_EFFECT && mIndex > 0 - && filmRatio != 1f && !mPictures.get(0).isCamera(); - boolean wantsOffsetEffect = OFFSET_EFFECT && mIsDeletable - && filmRatio == 1f && r.centerY() != h / 2; - int cx = wantsCardEffect - ? (int) (interpolate(filmRatio, w / 2, r.centerX()) + 0.5f) - : r.centerX(); - int cy = r.centerY(); - canvas.save(GLCanvas.SAVE_FLAG_MATRIX | GLCanvas.SAVE_FLAG_ALPHA); - canvas.translate(cx, cy); - if (wantsCardEffect) { - float progress = (float) (w / 2 - r.centerX()) / w; - progress = Utils.clamp(progress, -1, 1); - float alpha = getScrollAlpha(progress); - float scale = getScrollScale(progress); - alpha = interpolate(filmRatio, alpha, 1f); - scale = interpolate(filmRatio, scale, 1f); - canvas.multiplyAlpha(alpha); - canvas.scale(scale, scale, 1); - } else if (wantsOffsetEffect) { - float offset = (float) (r.centerY() - h / 2) / h; - float alpha = getOffsetAlpha(offset); - canvas.multiplyAlpha(alpha); - } - if (mRotation != 0) { - canvas.rotate(mRotation, 0, 0, 1); - } - int drawW = getRotated(mRotation, r.width(), r.height()); - int drawH = getRotated(mRotation, r.height(), r.width()); - mScreenNail.draw(canvas, -drawW / 2, -drawH / 2, drawW, drawH); - if (isScreenNailAnimating()) { - invalidate(); - } - int s = Math.min(drawW, drawH); - if (mIsVideo) drawVideoPlayIcon(canvas, s); - if (mLoadingState == Model.LOADING_FAIL) { - drawLoadingFailMessage(canvas); - } - canvas.restore(); - } - - private boolean isScreenNailAnimating() { - return (mScreenNail instanceof TiledScreenNail) - && ((TiledScreenNail) mScreenNail).isAnimating(); - } - - @Override - public void setScreenNail(ScreenNail s) { - mScreenNail = s; - } - - @Override - public void forceSize() { - updateSize(); - mPositionController.forceImageSize(mIndex, mSize); - } - - private void updateSize() { - if (mIsPanorama) { - mRotation = getPanoramaRotation(); - } else if (mIsCamera && !mIsStaticCamera) { - mRotation = getCameraRotation(); - } else { - mRotation = mModel.getImageRotation(mIndex); - } - - if (mScreenNail != null) { - mSize.width = mScreenNail.getWidth(); - mSize.height = mScreenNail.getHeight(); - } else { - // If we don't have ScreenNail available, we can still try to - // get the size information of it. - mModel.getImageSize(mIndex, mSize); - } - - int w = mSize.width; - int h = mSize.height; - mSize.width = getRotated(mRotation, w, h); - mSize.height = getRotated(mRotation, h, w); - } - - @Override - public boolean isCamera() { - return mIsCamera; - } - - @Override - public boolean isDeletable() { - return mIsDeletable; - } - } - - // Draw a gray placeholder in the specified rectangle. - private void drawPlaceHolder(GLCanvas canvas, Rect r) { - canvas.fillRect(r.left, r.top, r.width(), r.height(), mPlaceholderColor); - } - - // Draw the video play icon (in the place where the spinner was) - private void drawVideoPlayIcon(GLCanvas canvas, int side) { - int s = side / ICON_RATIO; - // Draw the video play icon at the center - mVideoPlayIcon.draw(canvas, -s / 2, -s / 2, s, s); - } - - // Draw the "no thumbnail" message - private void drawLoadingFailMessage(GLCanvas canvas) { - StringTexture m = mNoThumbnailText; - m.draw(canvas, -m.getWidth() / 2, -m.getHeight() / 2); - } - - private static int getRotated(int degree, int original, int theother) { - return (degree % 180 == 0) ? original : theother; - } - - //////////////////////////////////////////////////////////////////////////// - // Gestures Handling - //////////////////////////////////////////////////////////////////////////// - - @Override - protected boolean onTouch(MotionEvent event) { - mGestureRecognizer.onTouchEvent(event); - return true; - } - - private class MyGestureListener implements GestureRecognizer.Listener { - private boolean mIgnoreUpEvent = false; - // If we can change mode for this scale gesture. - private boolean mCanChangeMode; - // If we have changed the film mode in this scaling gesture. - private boolean mModeChanged; - // If this scaling gesture should be ignored. - private boolean mIgnoreScalingGesture; - // whether the down action happened while the view is scrolling. - private boolean mDownInScrolling; - // If we should ignore all gestures other than onSingleTapUp. - private boolean mIgnoreSwipingGesture; - // If a scrolling has happened after a down gesture. - private boolean mScrolledAfterDown; - // If the first scrolling move is in X direction. In the film mode, X - // direction scrolling is normal scrolling. but Y direction scrolling is - // a delete gesture. - private boolean mFirstScrollX; - // The accumulated Y delta that has been sent to mPositionController. - private int mDeltaY; - // The accumulated scaling change from a scaling gesture. - private float mAccScale; - // If an onFling happened after the last onDown - private boolean mHadFling; - - @Override - public boolean onSingleTapUp(float x, float y) { - // On crespo running Android 2.3.6 (gingerbread), a pinch out gesture results in the - // following call sequence: onDown(), onUp() and then onSingleTapUp(). The correct - // sequence for a single-tap-up gesture should be: onDown(), onSingleTapUp() and onUp(). - // The call sequence for a pinch out gesture in JB is: onDown(), then onUp() and there's - // no onSingleTapUp(). Base on these observations, the following condition is added to - // filter out the false alarm where onSingleTapUp() is called within a pinch out - // gesture. The framework fix went into ICS. Refer to b/4588114. - if (Build.VERSION.SDK_INT < ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) { - if ((mHolding & HOLD_TOUCH_DOWN) == 0) { - return true; - } - } - - // We do this in addition to onUp() because we want the snapback of - // setFilmMode to happen. - mHolding &= ~HOLD_TOUCH_DOWN; - - if (mFilmMode && !mDownInScrolling) { - switchToHitPicture((int) (x + 0.5f), (int) (y + 0.5f)); - - // If this is a lock screen photo, let the listener handle the - // event. Tapping on lock screen photo should take the user - // directly to the lock screen. - MediaItem item = mModel.getMediaItem(0); - int supported = 0; - if (item != null) supported = item.getSupportedOperations(); - if ((supported & MediaItem.SUPPORT_ACTION) == 0) { - setFilmMode(false); - mIgnoreUpEvent = true; - return true; - } - } - - if (mListener != null) { - // Do the inverse transform of the touch coordinates. - Matrix m = getGLRoot().getCompensationMatrix(); - Matrix inv = new Matrix(); - m.invert(inv); - float[] pts = new float[] {x, y}; - inv.mapPoints(pts); - mListener.onSingleTapUp((int) (pts[0] + 0.5f), (int) (pts[1] + 0.5f)); - } - return true; - } - - @Override - public boolean onDoubleTap(float x, float y) { - if (mIgnoreSwipingGesture) return true; - if (mPictures.get(0).isCamera()) return false; - PositionController controller = mPositionController; - float scale = controller.getImageScale(); - // onDoubleTap happened on the second ACTION_DOWN. - // We need to ignore the next UP event. - mIgnoreUpEvent = true; - if (scale <= .75f || controller.isAtMinimalScale()) { - controller.zoomIn(x, y, Math.max(1.0f, scale * 1.5f)); - } else { - controller.resetToFullView(); - } - return true; - } - - @Override - public boolean onScroll(float dx, float dy, float totalX, float totalY) { - if (mIgnoreSwipingGesture) return true; - if (!mScrolledAfterDown) { - mScrolledAfterDown = true; - mFirstScrollX = (Math.abs(dx) > Math.abs(dy)); - } - - int dxi = (int) (-dx + 0.5f); - int dyi = (int) (-dy + 0.5f); - if (mFilmMode) { - if (mFirstScrollX) { - mPositionController.scrollFilmX(dxi); - } else { - if (mTouchBoxIndex == Integer.MAX_VALUE) return true; - int newDeltaY = calculateDeltaY(totalY); - int d = newDeltaY - mDeltaY; - if (d != 0) { - mPositionController.scrollFilmY(mTouchBoxIndex, d); - mDeltaY = newDeltaY; - } - } - } else { - mPositionController.scrollPage(dxi, dyi); - } - return true; - } - - private int calculateDeltaY(float delta) { - if (mTouchBoxDeletable) return (int) (delta + 0.5f); - - // don't let items that can't be deleted be dragged more than - // maxScrollDistance, and make it harder and harder to drag. - int size = getHeight(); - float maxScrollDistance = 0.15f * size; - if (Math.abs(delta) >= size) { - delta = delta > 0 ? maxScrollDistance : -maxScrollDistance; - } else { - delta = maxScrollDistance * - FloatMath.sin((delta / size) * (float) (Math.PI / 2)); - } - return (int) (delta + 0.5f); - } - - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if (mIgnoreSwipingGesture) return true; - if (mModeChanged) return true; - if (swipeImages(velocityX, velocityY)) { - mIgnoreUpEvent = true; - } else { - flingImages(velocityX, velocityY, Math.abs(e2.getY() - e1.getY())); - } - mHadFling = true; - return true; - } - - private boolean flingImages(float velocityX, float velocityY, float dY) { - int vx = (int) (velocityX + 0.5f); - int vy = (int) (velocityY + 0.5f); - if (!mFilmMode) { - return mPositionController.flingPage(vx, vy); - } - if (Math.abs(velocityX) > Math.abs(velocityY)) { - return mPositionController.flingFilmX(vx); - } - // If we scrolled in Y direction fast enough, treat it as a delete - // gesture. - if (!mFilmMode || mTouchBoxIndex == Integer.MAX_VALUE - || !mTouchBoxDeletable) { - return false; - } - int maxVelocity = GalleryUtils.dpToPixel(MAX_DISMISS_VELOCITY); - int escapeVelocity = GalleryUtils.dpToPixel(SWIPE_ESCAPE_VELOCITY); - int escapeDistance = GalleryUtils.dpToPixel(SWIPE_ESCAPE_DISTANCE); - int centerY = mPositionController.getPosition(mTouchBoxIndex) - .centerY(); - boolean fastEnough = (Math.abs(vy) > escapeVelocity) - && (Math.abs(vy) > Math.abs(vx)) - && ((vy > 0) == (centerY > getHeight() / 2)) - && dY >= escapeDistance; - if (fastEnough) { - vy = Math.min(vy, maxVelocity); - int duration = mPositionController.flingFilmY(mTouchBoxIndex, vy); - if (duration >= 0) { - mPositionController.setPopFromTop(vy < 0); - deleteAfterAnimation(duration); - // We reset mTouchBoxIndex, so up() won't check if Y - // scrolled far enough to be a delete gesture. - mTouchBoxIndex = Integer.MAX_VALUE; - return true; - } - } - return false; - } - - private void deleteAfterAnimation(int duration) { - MediaItem item = mModel.getMediaItem(mTouchBoxIndex); - if (item == null) return; - mListener.onCommitDeleteImage(); - mUndoIndexHint = mModel.getCurrentIndex() + mTouchBoxIndex; - mHolding |= HOLD_DELETE; - Message m = mHandler.obtainMessage(MSG_DELETE_ANIMATION_DONE); - m.obj = item.getPath(); - m.arg1 = mTouchBoxIndex; - mHandler.sendMessageDelayed(m, duration); - } - - @Override - public boolean onScaleBegin(float focusX, float focusY) { - if (mIgnoreSwipingGesture) return true; - // We ignore the scaling gesture if it is a camera preview. - mIgnoreScalingGesture = mPictures.get(0).isCamera(); - if (mIgnoreScalingGesture) { - return true; - } - mPositionController.beginScale(focusX, focusY); - // We can change mode if we are in film mode, or we are in page - // mode and at minimal scale. - mCanChangeMode = mFilmMode - || mPositionController.isAtMinimalScale(); - mAccScale = 1f; - return true; - } - - @Override - public boolean onScale(float focusX, float focusY, float scale) { - if (mIgnoreSwipingGesture) return true; - if (mIgnoreScalingGesture) return true; - if (mModeChanged) return true; - if (Float.isNaN(scale) || Float.isInfinite(scale)) return false; - - int outOfRange = mPositionController.scaleBy(scale, focusX, focusY); - - // We wait for a large enough scale change before changing mode. - // Otherwise we may mistakenly treat a zoom-in gesture as zoom-out - // or vice versa. - mAccScale *= scale; - boolean largeEnough = (mAccScale < 0.97f || mAccScale > 1.03f); - - // If mode changes, we treat this scaling gesture has ended. - if (mCanChangeMode && largeEnough) { - if ((outOfRange < 0 && !mFilmMode) || - (outOfRange > 0 && mFilmMode)) { - stopExtraScalingIfNeeded(); - - // Removing the touch down flag allows snapback to happen - // for film mode change. - mHolding &= ~HOLD_TOUCH_DOWN; - if (mFilmMode) { - UsageStatistics.setPendingTransitionCause( - UsageStatistics.TRANSITION_PINCH_OUT); - } else { - UsageStatistics.setPendingTransitionCause( - UsageStatistics.TRANSITION_PINCH_IN); - } - setFilmMode(!mFilmMode); - - - // We need to call onScaleEnd() before setting mModeChanged - // to true. - onScaleEnd(); - mModeChanged = true; - return true; - } - } - - if (outOfRange != 0) { - startExtraScalingIfNeeded(); - } else { - stopExtraScalingIfNeeded(); - } - return true; - } - - @Override - public void onScaleEnd() { - if (mIgnoreSwipingGesture) return; - if (mIgnoreScalingGesture) return; - if (mModeChanged) return; - mPositionController.endScale(); - } - - private void startExtraScalingIfNeeded() { - if (!mCancelExtraScalingPending) { - mHandler.sendEmptyMessageDelayed( - MSG_CANCEL_EXTRA_SCALING, 700); - mPositionController.setExtraScalingRange(true); - mCancelExtraScalingPending = true; - } - } - - private void stopExtraScalingIfNeeded() { - if (mCancelExtraScalingPending) { - mHandler.removeMessages(MSG_CANCEL_EXTRA_SCALING); - mPositionController.setExtraScalingRange(false); - mCancelExtraScalingPending = false; - } - } - - @Override - public void onDown(float x, float y) { - checkHideUndoBar(UNDO_BAR_TOUCHED); - - mDeltaY = 0; - mModeChanged = false; - - if (mIgnoreSwipingGesture) return; - - mHolding |= HOLD_TOUCH_DOWN; - - if (mFilmMode && mPositionController.isScrolling()) { - mDownInScrolling = true; - mPositionController.stopScrolling(); - } else { - mDownInScrolling = false; - } - mHadFling = false; - mScrolledAfterDown = false; - if (mFilmMode) { - int xi = (int) (x + 0.5f); - int yi = (int) (y + 0.5f); - // We only care about being within the x bounds, necessary for - // handling very wide images which are otherwise very hard to fling - mTouchBoxIndex = mPositionController.hitTest(xi, getHeight() / 2); - - if (mTouchBoxIndex < mPrevBound || mTouchBoxIndex > mNextBound) { - mTouchBoxIndex = Integer.MAX_VALUE; - } else { - mTouchBoxDeletable = - mPictures.get(mTouchBoxIndex).isDeletable(); - } - } else { - mTouchBoxIndex = Integer.MAX_VALUE; - } - } - - @Override - public void onUp() { - if (mIgnoreSwipingGesture) return; - - mHolding &= ~HOLD_TOUCH_DOWN; - mEdgeView.onRelease(); - - // If we scrolled in Y direction far enough, treat it as a delete - // gesture. - if (mFilmMode && mScrolledAfterDown && !mFirstScrollX - && mTouchBoxIndex != Integer.MAX_VALUE) { - Rect r = mPositionController.getPosition(mTouchBoxIndex); - int h = getHeight(); - if (Math.abs(r.centerY() - h * 0.5f) > 0.4f * h) { - int duration = mPositionController - .flingFilmY(mTouchBoxIndex, 0); - if (duration >= 0) { - mPositionController.setPopFromTop(r.centerY() < h * 0.5f); - deleteAfterAnimation(duration); - } - } - } - - if (mIgnoreUpEvent) { - mIgnoreUpEvent = false; - return; - } - - if (!(mFilmMode && !mHadFling && mFirstScrollX - && snapToNeighborImage())) { - snapback(); - } - } - - public void setSwipingEnabled(boolean enabled) { - mIgnoreSwipingGesture = !enabled; - } - } - - public void setSwipingEnabled(boolean enabled) { - mGestureListener.setSwipingEnabled(enabled); - } - - private void updateActionBar() { - boolean isCamera = mPictures.get(0).isCamera(); - if (isCamera && !mFilmMode) { - // Move into camera in page mode, lock - mListener.onActionBarAllowed(false); - } else { - mListener.onActionBarAllowed(true); - if (mFilmMode) mListener.onActionBarWanted(); - } - } - - public void setFilmMode(boolean enabled) { - if (mFilmMode == enabled) return; - mFilmMode = enabled; - mPositionController.setFilmMode(mFilmMode); - mModel.setNeedFullImage(!enabled); - mModel.setFocusHintDirection( - mFilmMode ? Model.FOCUS_HINT_PREVIOUS : Model.FOCUS_HINT_NEXT); - updateActionBar(); - mListener.onFilmModeChanged(enabled); - } - - public boolean getFilmMode() { - return mFilmMode; - } - - //////////////////////////////////////////////////////////////////////////// - // Framework events - //////////////////////////////////////////////////////////////////////////// - - public void pause() { - mPositionController.skipAnimation(); - mTileView.freeTextures(); - for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; i++) { - mPictures.get(i).setScreenNail(null); - } - hideUndoBar(); - } - - public void resume() { - mTileView.prepareTextures(); - mPositionController.skipToFinalPosition(); - } - - // move to the camera preview and show controls after resume - public void resetToFirstPicture() { - mModel.moveTo(0); - setFilmMode(false); - } - - //////////////////////////////////////////////////////////////////////////// - // Undo Bar - //////////////////////////////////////////////////////////////////////////// - - private int mUndoBarState; - private static final int UNDO_BAR_SHOW = 1; - private static final int UNDO_BAR_TIMEOUT = 2; - private static final int UNDO_BAR_TOUCHED = 4; - private static final int UNDO_BAR_FULL_CAMERA = 8; - private static final int UNDO_BAR_DELETE_LAST = 16; - - // "deleteLast" means if the deletion is on the last remaining picture in - // the album. - private void showUndoBar(boolean deleteLast) { - mHandler.removeMessages(MSG_UNDO_BAR_TIMEOUT); - mUndoBarState = UNDO_BAR_SHOW; - if(deleteLast) mUndoBarState |= UNDO_BAR_DELETE_LAST; - mUndoBar.animateVisibility(GLView.VISIBLE); - mHandler.sendEmptyMessageDelayed(MSG_UNDO_BAR_TIMEOUT, 3000); - if (mListener != null) mListener.onUndoBarVisibilityChanged(true); - } - - private void hideUndoBar() { - mHandler.removeMessages(MSG_UNDO_BAR_TIMEOUT); - mListener.onCommitDeleteImage(); - mUndoBar.animateVisibility(GLView.INVISIBLE); - mUndoBarState = 0; - mUndoIndexHint = Integer.MAX_VALUE; - mListener.onUndoBarVisibilityChanged(false); - } - - // Check if the one of the conditions for hiding the undo bar has been - // met. The conditions are: - // - // 1. It has been three seconds since last showing, and (a) the user has - // touched, or (b) the deleted picture is the last remaining picture in the - // album. - // - // 2. The camera is shown in full screen. - private void checkHideUndoBar(int addition) { - mUndoBarState |= addition; - if ((mUndoBarState & UNDO_BAR_SHOW) == 0) return; - boolean timeout = (mUndoBarState & UNDO_BAR_TIMEOUT) != 0; - boolean touched = (mUndoBarState & UNDO_BAR_TOUCHED) != 0; - boolean fullCamera = (mUndoBarState & UNDO_BAR_FULL_CAMERA) != 0; - boolean deleteLast = (mUndoBarState & UNDO_BAR_DELETE_LAST) != 0; - if ((timeout && deleteLast) || fullCamera || touched) { - hideUndoBar(); - } - } - - public boolean canUndo() { - return (mUndoBarState & UNDO_BAR_SHOW) != 0; - } - - //////////////////////////////////////////////////////////////////////////// - // Rendering - //////////////////////////////////////////////////////////////////////////// - - @Override - protected void render(GLCanvas canvas) { - if (mFirst) { - // Make sure the fields are properly initialized before checking - // whether isCamera() - mPictures.get(0).reload(); - } - // Check if the camera preview occupies the full screen. - boolean full = !mFilmMode && mPictures.get(0).isCamera() - && mPositionController.isCenter() - && mPositionController.isAtMinimalScale(); - if (mFirst || full != mFullScreenCamera) { - mFullScreenCamera = full; - mFirst = false; - mListener.onFullScreenChanged(full); - if (full) mHandler.sendEmptyMessage(MSG_UNDO_BAR_FULL_CAMERA); - } - - // Determine how many photos we need to draw in addition to the center - // one. - int neighbors; - if (mFullScreenCamera) { - neighbors = 0; - } else { - // In page mode, we draw only one previous/next photo. But if we are - // doing capture animation, we want to draw all photos. - boolean inPageMode = (mPositionController.getFilmRatio() == 0f); - boolean inCaptureAnimation = - ((mHolding & HOLD_CAPTURE_ANIMATION) != 0); - if (inPageMode && !inCaptureAnimation) { - neighbors = 1; - } else { - neighbors = SCREEN_NAIL_MAX; - } - } - - // Draw photos from back to front - for (int i = neighbors; i >= -neighbors; i--) { - Rect r = mPositionController.getPosition(i); - mPictures.get(i).draw(canvas, r); - } - - renderChild(canvas, mEdgeView); - renderChild(canvas, mUndoBar); - - mPositionController.advanceAnimation(); - checkFocusSwitching(); - } - - //////////////////////////////////////////////////////////////////////////// - // Film mode focus switching - //////////////////////////////////////////////////////////////////////////// - - // Runs in GL thread. - private void checkFocusSwitching() { - if (!mFilmMode) return; - if (mHandler.hasMessages(MSG_SWITCH_FOCUS)) return; - if (switchPosition() != 0) { - mHandler.sendEmptyMessage(MSG_SWITCH_FOCUS); - } - } - - // Runs in main thread. - private void switchFocus() { - if (mHolding != 0) return; - switch (switchPosition()) { - case -1: - switchToPrevImage(); - break; - case 1: - switchToNextImage(); - break; - } - } - - // Returns -1 if we should switch focus to the previous picture, +1 if we - // should switch to the next, 0 otherwise. - private int switchPosition() { - Rect curr = mPositionController.getPosition(0); - int center = getWidth() / 2; - - if (curr.left > center && mPrevBound < 0) { - Rect prev = mPositionController.getPosition(-1); - int currDist = curr.left - center; - int prevDist = center - prev.right; - if (prevDist < currDist) { - return -1; - } - } else if (curr.right < center && mNextBound > 0) { - Rect next = mPositionController.getPosition(1); - int currDist = center - curr.right; - int nextDist = next.left - center; - if (nextDist < currDist) { - return 1; - } - } - - return 0; - } - - // Switch to the previous or next picture if the hit position is inside - // one of their boxes. This runs in main thread. - private void switchToHitPicture(int x, int y) { - if (mPrevBound < 0) { - Rect r = mPositionController.getPosition(-1); - if (r.right >= x) { - slideToPrevPicture(); - return; - } - } - - if (mNextBound > 0) { - Rect r = mPositionController.getPosition(1); - if (r.left <= x) { - slideToNextPicture(); - return; - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // Page mode focus switching - // - // We slide image to the next one or the previous one in two cases: 1: If - // the user did a fling gesture with enough velocity. 2 If the user has - // moved the picture a lot. - //////////////////////////////////////////////////////////////////////////// - - private boolean swipeImages(float velocityX, float velocityY) { - if (mFilmMode) return false; - - // Avoid swiping images if we're possibly flinging to view the - // zoomed in picture vertically. - PositionController controller = mPositionController; - boolean isMinimal = controller.isAtMinimalScale(); - int edges = controller.getImageAtEdges(); - if (!isMinimal && Math.abs(velocityY) > Math.abs(velocityX)) - if ((edges & PositionController.IMAGE_AT_TOP_EDGE) == 0 - || (edges & PositionController.IMAGE_AT_BOTTOM_EDGE) == 0) - return false; - - // If we are at the edge of the current photo and the sweeping velocity - // exceeds the threshold, slide to the next / previous image. - if (velocityX < -SWIPE_THRESHOLD && (isMinimal - || (edges & PositionController.IMAGE_AT_RIGHT_EDGE) != 0)) { - return slideToNextPicture(); - } else if (velocityX > SWIPE_THRESHOLD && (isMinimal - || (edges & PositionController.IMAGE_AT_LEFT_EDGE) != 0)) { - return slideToPrevPicture(); - } - - return false; - } - - private void snapback() { - if ((mHolding & ~HOLD_DELETE) != 0) return; - if (mFilmMode || !snapToNeighborImage()) { - mPositionController.snapback(); - } - } - - private boolean snapToNeighborImage() { - Rect r = mPositionController.getPosition(0); - int viewW = getWidth(); - // Setting the move threshold proportional to the width of the view - int moveThreshold = viewW / 5 ; - int threshold = moveThreshold + gapToSide(r.width(), viewW); - - // If we have moved the picture a lot, switching. - if (viewW - r.right > threshold) { - return slideToNextPicture(); - } else if (r.left > threshold) { - return slideToPrevPicture(); - } - - return false; - } - - private boolean slideToNextPicture() { - if (mNextBound <= 0) return false; - switchToNextImage(); - mPositionController.startHorizontalSlide(); - return true; - } - - private boolean slideToPrevPicture() { - if (mPrevBound >= 0) return false; - switchToPrevImage(); - mPositionController.startHorizontalSlide(); - return true; - } - - private static int gapToSide(int imageWidth, int viewWidth) { - return Math.max(0, (viewWidth - imageWidth) / 2); - } - - //////////////////////////////////////////////////////////////////////////// - // Focus switching - //////////////////////////////////////////////////////////////////////////// - - public void switchToImage(int index) { - mModel.moveTo(index); - } - - private void switchToNextImage() { - mModel.moveTo(mModel.getCurrentIndex() + 1); - } - - private void switchToPrevImage() { - mModel.moveTo(mModel.getCurrentIndex() - 1); - } - - private void switchToFirstImage() { - mModel.moveTo(0); - } - - //////////////////////////////////////////////////////////////////////////// - // Opening Animation - //////////////////////////////////////////////////////////////////////////// - - public void setOpenAnimationRect(Rect rect) { - mPositionController.setOpenAnimationRect(rect); - } - - //////////////////////////////////////////////////////////////////////////// - // Capture Animation - //////////////////////////////////////////////////////////////////////////// - - public boolean switchWithCaptureAnimation(int offset) { - GLRoot root = getGLRoot(); - if(root == null) return false; - root.lockRenderThread(); - try { - return switchWithCaptureAnimationLocked(offset); - } finally { - root.unlockRenderThread(); - } - } - - private boolean switchWithCaptureAnimationLocked(int offset) { - if (mHolding != 0) return true; - if (offset == 1) { - if (mNextBound <= 0) return false; - // Temporary disable action bar until the capture animation is done. - if (!mFilmMode) mListener.onActionBarAllowed(false); - switchToNextImage(); - mPositionController.startCaptureAnimationSlide(-1); - } else if (offset == -1) { - if (mPrevBound >= 0) return false; - if (mFilmMode) setFilmMode(false); - - // If we are too far away from the first image (so that we don't - // have all the ScreenNails in-between), we go directly without - // animation. - if (mModel.getCurrentIndex() > SCREEN_NAIL_MAX) { - switchToFirstImage(); - mPositionController.skipToFinalPosition(); - return true; - } - - switchToFirstImage(); - mPositionController.startCaptureAnimationSlide(1); - } else { - return false; - } - mHolding |= HOLD_CAPTURE_ANIMATION; - Message m = mHandler.obtainMessage(MSG_CAPTURE_ANIMATION_DONE, offset, 0); - mHandler.sendMessageDelayed(m, PositionController.CAPTURE_ANIMATION_TIME); - return true; - } - - private void captureAnimationDone(int offset) { - mHolding &= ~HOLD_CAPTURE_ANIMATION; - if (offset == 1 && !mFilmMode) { - // Now the capture animation is done, enable the action bar. - mListener.onActionBarAllowed(true); - mListener.onActionBarWanted(); - } - snapback(); - } - - //////////////////////////////////////////////////////////////////////////// - // Card deck effect calculation - //////////////////////////////////////////////////////////////////////////// - - // Returns the scrolling progress value for an object moving out of a - // view. The progress value measures how much the object has moving out of - // the view. The object currently displays in [left, right), and the view is - // at [0, viewWidth]. - // - // The returned value is negative when the object is moving right, and - // positive when the object is moving left. The value goes to -1 or 1 when - // the object just moves out of the view completely. The value is 0 if the - // object currently fills the view. - private static float calculateMoveOutProgress(int left, int right, - int viewWidth) { - // w = object width - // viewWidth = view width - int w = right - left; - - // If the object width is smaller than the view width, - // |....view....| - // |<-->| progress = -1 when left = viewWidth - // |<-->| progress = 0 when left = viewWidth / 2 - w / 2 - // |<-->| progress = 1 when left = -w - if (w < viewWidth) { - int zx = viewWidth / 2 - w / 2; - if (left > zx) { - return -(left - zx) / (float) (viewWidth - zx); // progress = (0, -1] - } else { - return (left - zx) / (float) (-w - zx); // progress = [0, 1] - } - } - - // If the object width is larger than the view width, - // |..view..| - // |<--------->| progress = -1 when left = viewWidth - // |<--------->| progress = 0 between left = 0 - // |<--------->| and right = viewWidth - // |<--------->| progress = 1 when right = 0 - if (left > 0) { - return -left / (float) viewWidth; - } - - if (right < viewWidth) { - return (viewWidth - right) / (float) viewWidth; - } - - return 0; - } - - // Maps a scrolling progress value to the alpha factor in the fading - // animation. - private float getScrollAlpha(float scrollProgress) { - return scrollProgress < 0 ? mAlphaInterpolator.getInterpolation( - 1 - Math.abs(scrollProgress)) : 1.0f; - } - - // Maps a scrolling progress value to the scaling factor in the fading - // animation. - private float getScrollScale(float scrollProgress) { - float interpolatedProgress = mScaleInterpolator.getInterpolation( - Math.abs(scrollProgress)); - float scale = (1 - interpolatedProgress) + - interpolatedProgress * TRANSITION_SCALE_FACTOR; - return scale; - } - - - // This interpolator emulates the rate at which the perceived scale of an - // object changes as its distance from a camera increases. When this - // interpolator is applied to a scale animation on a view, it evokes the - // sense that the object is shrinking due to moving away from the camera. - private static class ZInterpolator { - private float focalLength; - - public ZInterpolator(float foc) { - focalLength = foc; - } - - public float getInterpolation(float input) { - return (1.0f - focalLength / (focalLength + input)) / - (1.0f - focalLength / (focalLength + 1.0f)); - } - } - - // Returns an interpolated value for the page/film transition. - // When ratio = 0, the result is from. - // When ratio = 1, the result is to. - private static float interpolate(float ratio, float from, float to) { - return from + (to - from) * ratio * ratio; - } - - // Returns the alpha factor in film mode if a picture is not in the center. - // The 0.03 lower bound is to make the item always visible a bit. - private float getOffsetAlpha(float offset) { - offset /= 0.5f; - float alpha = (offset > 0) ? (1 - offset) : (1 + offset); - return Utils.clamp(alpha, 0.03f, 1f); - } - - //////////////////////////////////////////////////////////////////////////// - // Simple public utilities - //////////////////////////////////////////////////////////////////////////// - - public void setListener(Listener listener) { - mListener = listener; - } - - public Rect getPhotoRect(int index) { - return mPositionController.getPosition(index); - } - - public PhotoFallbackEffect buildFallbackEffect(GLView root, GLCanvas canvas) { - Rect location = new Rect(); - Utils.assertTrue(root.getBoundsOf(this, location)); - - Rect fullRect = bounds(); - PhotoFallbackEffect effect = new PhotoFallbackEffect(); - for (int i = -SCREEN_NAIL_MAX; i <= SCREEN_NAIL_MAX; ++i) { - MediaItem item = mModel.getMediaItem(i); - if (item == null) continue; - ScreenNail sc = mModel.getScreenNail(i); - if (!(sc instanceof TiledScreenNail) - || ((TiledScreenNail) sc).isShowingPlaceholder()) continue; - - // Now, sc is BitmapScreenNail and is not showing placeholder - Rect rect = new Rect(getPhotoRect(i)); - if (!Rect.intersects(fullRect, rect)) continue; - rect.offset(location.left, location.top); - - int width = sc.getWidth(); - int height = sc.getHeight(); - - int rotation = mModel.getImageRotation(i); - RawTexture texture; - if ((rotation % 180) == 0) { - texture = new RawTexture(width, height, true); - canvas.beginRenderTarget(texture); - canvas.translate(width / 2f, height / 2f); - } else { - texture = new RawTexture(height, width, true); - canvas.beginRenderTarget(texture); - canvas.translate(height / 2f, width / 2f); - } - - canvas.rotate(rotation, 0, 0, 1); - canvas.translate(-width / 2f, -height / 2f); - sc.draw(canvas, 0, 0, width, height); - canvas.endRenderTarget(); - effect.addEntry(item.getPath(), rect, texture); - } - return effect; - } -} diff --git a/src/com/android/gallery3d/ui/PopupList.java b/src/com/android/gallery3d/ui/PopupList.java deleted file mode 100644 index 248f50b25..000000000 --- a/src/com/android/gallery3d/ui/PopupList.java +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.content.Context; -import android.graphics.Rect; -import android.view.LayoutInflater; -import android.view.View; -import android.view.View.MeasureSpec; -import android.view.ViewGroup; -import android.view.ViewTreeObserver; -import android.view.ViewTreeObserver.OnGlobalLayoutListener; -import android.widget.AdapterView; -import android.widget.AdapterView.OnItemClickListener; -import android.widget.BaseAdapter; -import android.widget.ListView; -import android.widget.PopupWindow; -import android.widget.TextView; - -import com.android.gallery3d.R; - -import java.util.ArrayList; - -public class PopupList { - - public static interface OnPopupItemClickListener { - public boolean onPopupItemClick(int itemId); - } - - public static class Item { - public final int id; - public String title; - - public Item(int id, String title) { - this.id = id; - this.title = title; - } - - public void setTitle(String title) { - this.title = title; - } - } - - private final Context mContext; - private final View mAnchorView; - private final ArrayList<Item> mItems = new ArrayList<Item>(); - private PopupWindow mPopupWindow; - private ListView mContentList; - private OnPopupItemClickListener mOnPopupItemClickListener; - private int mPopupOffsetX; - private int mPopupOffsetY; - private int mPopupWidth; - private int mPopupHeight; - - public PopupList(Context context, View anchorView) { - mContext = context; - mAnchorView = anchorView; - } - - public void setOnPopupItemClickListener(OnPopupItemClickListener listener) { - mOnPopupItemClickListener = listener; - } - - public void addItem(int id, String title) { - mItems.add(new Item(id, title)); - } - - public void clearItems() { - mItems.clear(); - } - - private final PopupWindow.OnDismissListener mOnDismissListener = - new PopupWindow.OnDismissListener() { - @SuppressWarnings("deprecation") - @Override - public void onDismiss() { - if (mPopupWindow == null) return; - mPopupWindow = null; - ViewTreeObserver observer = mAnchorView.getViewTreeObserver(); - if (observer.isAlive()) { - // We used the deprecated function for backward compatibility - // The new "removeOnGlobalLayoutListener" is introduced in API level 16 - observer.removeGlobalOnLayoutListener(mOnGLobalLayoutListener); - } - } - }; - - private final OnItemClickListener mOnItemClickListener = - new OnItemClickListener() { - @Override - public void onItemClick(AdapterView<?> parent, View view, int position, long id) { - if (mPopupWindow == null) return; - mPopupWindow.dismiss(); - if (mOnPopupItemClickListener != null) { - mOnPopupItemClickListener.onPopupItemClick((int) id); - } - } - }; - - private final OnGlobalLayoutListener mOnGLobalLayoutListener = - new OnGlobalLayoutListener() { - @Override - public void onGlobalLayout() { - if (mPopupWindow == null) return; - updatePopupLayoutParams(); - // Need to update the position of the popup window - mPopupWindow.update(mAnchorView, - mPopupOffsetX, mPopupOffsetY, mPopupWidth, mPopupHeight); - } - }; - - public void show() { - if (mPopupWindow != null) return; - mAnchorView.getViewTreeObserver() - .addOnGlobalLayoutListener(mOnGLobalLayoutListener); - mPopupWindow = createPopupWindow(); - updatePopupLayoutParams(); - mPopupWindow.setWidth(mPopupWidth); - mPopupWindow.setHeight(mPopupHeight); - mPopupWindow.showAsDropDown(mAnchorView, mPopupOffsetX, mPopupOffsetY); - } - - private void updatePopupLayoutParams() { - ListView content = mContentList; - PopupWindow popup = mPopupWindow; - - Rect p = new Rect(); - popup.getBackground().getPadding(p); - - int maxHeight = mPopupWindow.getMaxAvailableHeight(mAnchorView) - p.top - p.bottom; - mContentList.measure( - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), - MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.AT_MOST)); - mPopupWidth = content.getMeasuredWidth() + p.top + p.bottom; - mPopupHeight = Math.min(maxHeight, content.getMeasuredHeight() + p.left + p.right); - mPopupOffsetX = -p.left; - mPopupOffsetY = -p.top; - } - - private PopupWindow createPopupWindow() { - PopupWindow popup = new PopupWindow(mContext); - popup.setOnDismissListener(mOnDismissListener); - - popup.setBackgroundDrawable(mContext.getResources().getDrawable( - R.drawable.menu_dropdown_panel_holo_dark)); - - mContentList = new ListView(mContext, null, - android.R.attr.dropDownListViewStyle); - mContentList.setAdapter(new ItemDataAdapter()); - mContentList.setOnItemClickListener(mOnItemClickListener); - popup.setContentView(mContentList); - popup.setFocusable(true); - popup.setOutsideTouchable(true); - - return popup; - } - - public Item findItem(int id) { - for (Item item : mItems) { - if (item.id == id) return item; - } - return null; - } - - private class ItemDataAdapter extends BaseAdapter { - @Override - public int getCount() { - return mItems.size(); - } - - @Override - public Object getItem(int position) { - return mItems.get(position); - } - - @Override - public long getItemId(int position) { - return mItems.get(position).id; - } - - @Override - public View getView(int position, View convertView, ViewGroup parent) { - if (convertView == null) { - convertView = LayoutInflater.from(mContext) - .inflate(R.layout.popup_list_item, null); - } - TextView text = (TextView) convertView.findViewById(android.R.id.text1); - text.setText(mItems.get(position).title); - return convertView; - } - } -} diff --git a/src/com/android/gallery3d/ui/PositionController.java b/src/com/android/gallery3d/ui/PositionController.java deleted file mode 100644 index 6a4bcea87..000000000 --- a/src/com/android/gallery3d/ui/PositionController.java +++ /dev/null @@ -1,1821 +0,0 @@ -/* - * Copyright (C) 2011 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.ui; - -import android.content.Context; -import android.graphics.Rect; -import android.util.Log; -import android.widget.Scroller; - -import com.android.gallery3d.app.PhotoPage; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.ui.PhotoView.Size; -import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.RangeArray; -import com.android.gallery3d.util.RangeIntArray; - -class PositionController { - private static final String TAG = "PositionController"; - - public static final int IMAGE_AT_LEFT_EDGE = 1; - public static final int IMAGE_AT_RIGHT_EDGE = 2; - public static final int IMAGE_AT_TOP_EDGE = 4; - public static final int IMAGE_AT_BOTTOM_EDGE = 8; - - public static final int CAPTURE_ANIMATION_TIME = 700; - public static final int SNAPBACK_ANIMATION_TIME = 600; - - // Special values for animation time. - private static final long NO_ANIMATION = -1; - private static final long LAST_ANIMATION = -2; - - private static final int ANIM_KIND_NONE = -1; - private static final int ANIM_KIND_SCROLL = 0; - private static final int ANIM_KIND_SCALE = 1; - private static final int ANIM_KIND_SNAPBACK = 2; - private static final int ANIM_KIND_SLIDE = 3; - private static final int ANIM_KIND_ZOOM = 4; - private static final int ANIM_KIND_OPENING = 5; - private static final int ANIM_KIND_FLING = 6; - private static final int ANIM_KIND_FLING_X = 7; - private static final int ANIM_KIND_DELETE = 8; - private static final int ANIM_KIND_CAPTURE = 9; - - // Animation time in milliseconds. The order must match ANIM_KIND_* above. - // - // The values for ANIM_KIND_FLING_X does't matter because we use - // mFilmScroller.isFinished() to decide when to stop. We set it to 0 so it's - // faster for Animatable.advanceAnimation() to calculate the progress - // (always 1). - private static final int ANIM_TIME[] = { - 0, // ANIM_KIND_SCROLL - 0, // ANIM_KIND_SCALE - SNAPBACK_ANIMATION_TIME, // ANIM_KIND_SNAPBACK - 400, // ANIM_KIND_SLIDE - 300, // ANIM_KIND_ZOOM - 300, // ANIM_KIND_OPENING - 0, // ANIM_KIND_FLING (the duration is calculated dynamically) - 0, // ANIM_KIND_FLING_X (see the comment above) - 0, // ANIM_KIND_DELETE (the duration is calculated dynamically) - CAPTURE_ANIMATION_TIME, // ANIM_KIND_CAPTURE - }; - - // We try to scale up the image to fill the screen. But in order not to - // scale too much for small icons, we limit the max up-scaling factor here. - private static final float SCALE_LIMIT = 4; - - // For user's gestures, we give a temporary extra scaling range which goes - // above or below the usual scaling limits. - private static final float SCALE_MIN_EXTRA = 0.7f; - private static final float SCALE_MAX_EXTRA = 1.4f; - - // Setting this true makes the extra scaling range permanent (until this is - // set to false again). - private boolean mExtraScalingRange = false; - - // Film Mode v.s. Page Mode: in film mode we show smaller pictures. - private boolean mFilmMode = false; - - // These are the limits for width / height of the picture in film mode. - private static final float FILM_MODE_PORTRAIT_HEIGHT = 0.48f; - private static final float FILM_MODE_PORTRAIT_WIDTH = 0.7f; - private static final float FILM_MODE_LANDSCAPE_HEIGHT = 0.7f; - private static final float FILM_MODE_LANDSCAPE_WIDTH = 0.7f; - - // In addition to the focused box (index == 0). We also keep information - // about this many boxes on each side. - private static final int BOX_MAX = PhotoView.SCREEN_NAIL_MAX; - private static final int[] CENTER_OUT_INDEX = new int[2 * BOX_MAX + 1]; - - private static final int IMAGE_GAP = GalleryUtils.dpToPixel(16); - private static final int HORIZONTAL_SLACK = GalleryUtils.dpToPixel(12); - - // These are constants for the delete gesture. - private static final int DEFAULT_DELETE_ANIMATION_DURATION = 200; // ms - private static final int MAX_DELETE_ANIMATION_DURATION = 400; // ms - - private Listener mListener; - private volatile Rect mOpenAnimationRect; - - // Use a large enough value, so we won't see the gray shadow in the beginning. - private int mViewW = 1200; - private int mViewH = 1200; - - // A scaling gesture is in progress. - private boolean mInScale; - // The focus point of the scaling gesture, relative to the center of the - // picture in bitmap pixels. - private float mFocusX, mFocusY; - - // whether there is a previous/next picture. - private boolean mHasPrev, mHasNext; - - // This is used by the fling animation (page mode). - private FlingScroller mPageScroller; - - // This is used by the fling animation (film mode). - private Scroller mFilmScroller; - - // The bound of the stable region that the focused box can stay, see the - // comments above calculateStableBound() for details. - private int mBoundLeft, mBoundRight, mBoundTop, mBoundBottom; - - // Constrained frame is a rectangle that the focused box should fit into if - // it is constrained. It has two effects: - // - // (1) In page mode, if the focused box is constrained, scaling for the - // focused box is adjusted to fit into the constrained frame, instead of the - // whole view. - // - // (2) In page mode, if the focused box is constrained, the mPlatform's - // default center (mDefaultX/Y) is moved to the center of the constrained - // frame, instead of the view center. - // - private Rect mConstrainedFrame = new Rect(); - - // Whether the focused box is constrained. - // - // Our current program's first call to moveBox() sets constrained = true, so - // we set the initial value of this variable to true, and we will not see - // see unwanted transition animation. - private boolean mConstrained = true; - - // - // ___________________________________________________________ - // | _____ _____ _____ _____ _____ | - // | | | | | | | | | | | | - // | | Box | | Box | | Box*| | Box | | Box | | - // | |_____|.....|_____|.....|_____|.....|_____|.....|_____| | - // | Gap Gap Gap Gap | - // |___________________________________________________________| - // - // <-- Platform --> - // - // The focused box (Box*) centers at mPlatform's (mCurrentX, mCurrentY) - - private Platform mPlatform = new Platform(); - private RangeArray<Box> mBoxes = new RangeArray<Box>(-BOX_MAX, BOX_MAX); - // The gap at the right of a Box i is at index i. The gap at the left of a - // Box i is at index i - 1. - private RangeArray<Gap> mGaps = new RangeArray<Gap>(-BOX_MAX, BOX_MAX - 1); - private FilmRatio mFilmRatio = new FilmRatio(); - - // These are only used during moveBox(). - private RangeArray<Box> mTempBoxes = new RangeArray<Box>(-BOX_MAX, BOX_MAX); - private RangeArray<Gap> mTempGaps = - new RangeArray<Gap>(-BOX_MAX, BOX_MAX - 1); - - // The output of the PositionController. Available through getPosition(). - private RangeArray<Rect> mRects = new RangeArray<Rect>(-BOX_MAX, BOX_MAX); - - // The direction of a new picture should appear. New pictures pop from top - // if this value is true, or from bottom if this value is false. - boolean mPopFromTop; - - public interface Listener { - void invalidate(); - boolean isHoldingDown(); - boolean isHoldingDelete(); - - // EdgeView - void onPull(int offset, int direction); - void onRelease(); - void onAbsorb(int velocity, int direction); - } - - static { - // Initialize the CENTER_OUT_INDEX array. - // The array maps 0, 1, 2, 3, 4, ..., 2 * BOX_MAX - // to 0, 1, -1, 2, -2, ..., BOX_MAX, -BOX_MAX - for (int i = 0; i < CENTER_OUT_INDEX.length; i++) { - int j = (i + 1) / 2; - if ((i & 1) == 0) j = -j; - CENTER_OUT_INDEX[i] = j; - } - } - - public PositionController(Context context, Listener listener) { - mListener = listener; - mPageScroller = new FlingScroller(); - mFilmScroller = new Scroller(context, null, false); - - // Initialize the areas. - initPlatform(); - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - mBoxes.put(i, new Box()); - initBox(i); - mRects.put(i, new Rect()); - } - for (int i = -BOX_MAX; i < BOX_MAX; i++) { - mGaps.put(i, new Gap()); - initGap(i); - } - } - - public void setOpenAnimationRect(Rect r) { - mOpenAnimationRect = r; - } - - public void setViewSize(int viewW, int viewH) { - if (viewW == mViewW && viewH == mViewH) return; - - boolean wasMinimal = isAtMinimalScale(); - - mViewW = viewW; - mViewH = viewH; - initPlatform(); - - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - setBoxSize(i, viewW, viewH, true); - } - - updateScaleAndGapLimit(); - - // If the focused box was at minimal scale, we try to make it the - // minimal scale under the new view size. - if (wasMinimal) { - Box b = mBoxes.get(0); - b.mCurrentScale = b.mScaleMin; - } - - // If we have the opening animation, do it. Otherwise go directly to the - // right position. - if (!startOpeningAnimationIfNeeded()) { - skipToFinalPosition(); - } - } - - public void setConstrainedFrame(Rect cFrame) { - if (mConstrainedFrame.equals(cFrame)) return; - mConstrainedFrame.set(cFrame); - mPlatform.updateDefaultXY(); - updateScaleAndGapLimit(); - snapAndRedraw(); - } - - public void forceImageSize(int index, Size s) { - if (s.width == 0 || s.height == 0) return; - Box b = mBoxes.get(index); - b.mImageW = s.width; - b.mImageH = s.height; - return; - } - - public void setImageSize(int index, Size s, Rect cFrame) { - if (s.width == 0 || s.height == 0) return; - - boolean needUpdate = false; - if (cFrame != null && !mConstrainedFrame.equals(cFrame)) { - mConstrainedFrame.set(cFrame); - mPlatform.updateDefaultXY(); - needUpdate = true; - } - needUpdate |= setBoxSize(index, s.width, s.height, false); - - if (!needUpdate) return; - updateScaleAndGapLimit(); - snapAndRedraw(); - } - - // Returns false if the box size doesn't change. - private boolean setBoxSize(int i, int width, int height, boolean isViewSize) { - Box b = mBoxes.get(i); - boolean wasViewSize = b.mUseViewSize; - - // If we already have an image size, we don't want to use the view size. - if (!wasViewSize && isViewSize) return false; - - b.mUseViewSize = isViewSize; - - if (width == b.mImageW && height == b.mImageH) { - return false; - } - - // The ratio of the old size and the new size. - // - // If the aspect ratio changes, we don't know if it is because one side - // grows or the other side shrinks. Currently we just assume the view - // angle of the longer side doesn't change (so the aspect ratio change - // is because the view angle of the shorter side changes). This matches - // what camera preview does. - float ratio = (width > height) - ? (float) b.mImageW / width - : (float) b.mImageH / height; - - b.mImageW = width; - b.mImageH = height; - - // If this is the first time we receive an image size or we are in fullscreen, - // we change the scale directly. Otherwise adjust the scales by a ratio, - // and snapback will animate the scale into the min/max bounds if necessary. - if ((wasViewSize && !isViewSize) || !mFilmMode) { - b.mCurrentScale = getMinimalScale(b); - b.mAnimationStartTime = NO_ANIMATION; - } else { - b.mCurrentScale *= ratio; - b.mFromScale *= ratio; - b.mToScale *= ratio; - } - - if (i == 0) { - mFocusX /= ratio; - mFocusY /= ratio; - } - - return true; - } - - private boolean startOpeningAnimationIfNeeded() { - if (mOpenAnimationRect == null) return false; - Box b = mBoxes.get(0); - if (b.mUseViewSize) return false; - - // Start animation from the saved rectangle if we have one. - Rect r = mOpenAnimationRect; - mOpenAnimationRect = null; - - mPlatform.mCurrentX = r.centerX() - mViewW / 2; - b.mCurrentY = r.centerY() - mViewH / 2; - b.mCurrentScale = Math.max(r.width() / (float) b.mImageW, - r.height() / (float) b.mImageH); - startAnimation(mPlatform.mDefaultX, 0, b.mScaleMin, - ANIM_KIND_OPENING); - - // Animate from large gaps for neighbor boxes to avoid them - // shown on the screen during opening animation. - for (int i = -1; i < 1; i++) { - Gap g = mGaps.get(i); - g.mCurrentGap = mViewW; - g.doAnimation(g.mDefaultSize, ANIM_KIND_OPENING); - } - - return true; - } - - public void setFilmMode(boolean enabled) { - if (enabled == mFilmMode) return; - mFilmMode = enabled; - - mPlatform.updateDefaultXY(); - updateScaleAndGapLimit(); - stopAnimation(); - snapAndRedraw(); - } - - public void setExtraScalingRange(boolean enabled) { - if (mExtraScalingRange == enabled) return; - mExtraScalingRange = enabled; - if (!enabled) { - snapAndRedraw(); - } - } - - // This should be called whenever the scale range of boxes or the default - // gap size may change. Currently this can happen due to change of view - // size, image size, mFilmMode, mConstrained, and mConstrainedFrame. - private void updateScaleAndGapLimit() { - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - Box b = mBoxes.get(i); - b.mScaleMin = getMinimalScale(b); - b.mScaleMax = getMaximalScale(b); - } - - for (int i = -BOX_MAX; i < BOX_MAX; i++) { - Gap g = mGaps.get(i); - g.mDefaultSize = getDefaultGapSize(i); - } - } - - // Returns the default gap size according the the size of the boxes around - // the gap and the current mode. - private int getDefaultGapSize(int i) { - if (mFilmMode) return IMAGE_GAP; - Box a = mBoxes.get(i); - Box b = mBoxes.get(i + 1); - return IMAGE_GAP + Math.max(gapToSide(a), gapToSide(b)); - } - - // Here is how we layout the boxes in the page mode. - // - // previous current next - // ___________ ________________ __________ - // | _______ | | __________ | | ______ | - // | | | | | | right->| | | | | | - // | | |<-------->|<--left | | | | | | - // | |_______| | | | |__________| | | |______| | - // |___________| | |________________| |__________| - // | <--> gapToSide() - // | - // IMAGE_GAP + MAX(gapToSide(previous), gapToSide(current)) - private int gapToSide(Box b) { - return (int) ((mViewW - getMinimalScale(b) * b.mImageW) / 2 + 0.5f); - } - - // Stop all animations at where they are now. - public void stopAnimation() { - mPlatform.mAnimationStartTime = NO_ANIMATION; - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - mBoxes.get(i).mAnimationStartTime = NO_ANIMATION; - } - for (int i = -BOX_MAX; i < BOX_MAX; i++) { - mGaps.get(i).mAnimationStartTime = NO_ANIMATION; - } - } - - public void skipAnimation() { - if (mPlatform.mAnimationStartTime != NO_ANIMATION) { - mPlatform.mCurrentX = mPlatform.mToX; - mPlatform.mCurrentY = mPlatform.mToY; - mPlatform.mAnimationStartTime = NO_ANIMATION; - } - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - Box b = mBoxes.get(i); - if (b.mAnimationStartTime == NO_ANIMATION) continue; - b.mCurrentY = b.mToY; - b.mCurrentScale = b.mToScale; - b.mAnimationStartTime = NO_ANIMATION; - } - for (int i = -BOX_MAX; i < BOX_MAX; i++) { - Gap g = mGaps.get(i); - if (g.mAnimationStartTime == NO_ANIMATION) continue; - g.mCurrentGap = g.mToGap; - g.mAnimationStartTime = NO_ANIMATION; - } - redraw(); - } - - public void snapback() { - snapAndRedraw(); - } - - public void skipToFinalPosition() { - stopAnimation(); - snapAndRedraw(); - skipAnimation(); - } - - //////////////////////////////////////////////////////////////////////////// - // Start an animations for the focused box - //////////////////////////////////////////////////////////////////////////// - - public void zoomIn(float tapX, float tapY, float targetScale) { - tapX -= mViewW / 2; - tapY -= mViewH / 2; - Box b = mBoxes.get(0); - - // Convert the tap position to distance to center in bitmap coordinates - float tempX = (tapX - mPlatform.mCurrentX) / b.mCurrentScale; - float tempY = (tapY - b.mCurrentY) / b.mCurrentScale; - - int x = (int) (-tempX * targetScale + 0.5f); - int y = (int) (-tempY * targetScale + 0.5f); - - calculateStableBound(targetScale); - int targetX = Utils.clamp(x, mBoundLeft, mBoundRight); - int targetY = Utils.clamp(y, mBoundTop, mBoundBottom); - targetScale = Utils.clamp(targetScale, b.mScaleMin, b.mScaleMax); - - startAnimation(targetX, targetY, targetScale, ANIM_KIND_ZOOM); - } - - public void resetToFullView() { - Box b = mBoxes.get(0); - startAnimation(mPlatform.mDefaultX, 0, b.mScaleMin, ANIM_KIND_ZOOM); - } - - public void beginScale(float focusX, float focusY) { - focusX -= mViewW / 2; - focusY -= mViewH / 2; - Box b = mBoxes.get(0); - Platform p = mPlatform; - mInScale = true; - mFocusX = (int) ((focusX - p.mCurrentX) / b.mCurrentScale + 0.5f); - mFocusY = (int) ((focusY - b.mCurrentY) / b.mCurrentScale + 0.5f); - } - - // Scales the image by the given factor. - // Returns an out-of-range indicator: - // 1 if the intended scale is too large for the stable range. - // 0 if the intended scale is in the stable range. - // -1 if the intended scale is too small for the stable range. - public int scaleBy(float s, float focusX, float focusY) { - focusX -= mViewW / 2; - focusY -= mViewH / 2; - Box b = mBoxes.get(0); - Platform p = mPlatform; - - // We want to keep the focus point (on the bitmap) the same as when we - // begin the scale gesture, that is, - // - // (focusX' - currentX') / scale' = (focusX - currentX) / scale - // - s = b.clampScale(s * getTargetScale(b)); - int x = mFilmMode ? p.mCurrentX : (int) (focusX - s * mFocusX + 0.5f); - int y = mFilmMode ? b.mCurrentY : (int) (focusY - s * mFocusY + 0.5f); - startAnimation(x, y, s, ANIM_KIND_SCALE); - if (s < b.mScaleMin) return -1; - if (s > b.mScaleMax) return 1; - return 0; - } - - public void endScale() { - mInScale = false; - snapAndRedraw(); - } - - // Slide the focused box to the center of the view. - public void startHorizontalSlide() { - Box b = mBoxes.get(0); - startAnimation(mPlatform.mDefaultX, 0, b.mScaleMin, ANIM_KIND_SLIDE); - } - - // Slide the focused box to the center of the view with the capture - // animation. In addition to the sliding, the animation will also scale the - // the focused box, the specified neighbor box, and the gap between the - // two. The specified offset should be 1 or -1. - public void startCaptureAnimationSlide(int offset) { - Box b = mBoxes.get(0); - Box n = mBoxes.get(offset); // the neighbor box - Gap g = mGaps.get(offset); // the gap between the two boxes - - mPlatform.doAnimation(mPlatform.mDefaultX, mPlatform.mDefaultY, - ANIM_KIND_CAPTURE); - b.doAnimation(0, b.mScaleMin, ANIM_KIND_CAPTURE); - n.doAnimation(0, n.mScaleMin, ANIM_KIND_CAPTURE); - g.doAnimation(g.mDefaultSize, ANIM_KIND_CAPTURE); - redraw(); - } - - // Only allow scrolling when we are not currently in an animation or we - // are in some animation with can be interrupted. - private boolean canScroll() { - Box b = mBoxes.get(0); - if (b.mAnimationStartTime == NO_ANIMATION) return true; - switch (b.mAnimationKind) { - case ANIM_KIND_SCROLL: - case ANIM_KIND_FLING: - case ANIM_KIND_FLING_X: - return true; - } - return false; - } - - public void scrollPage(int dx, int dy) { - if (!canScroll()) return; - - Box b = mBoxes.get(0); - Platform p = mPlatform; - - calculateStableBound(b.mCurrentScale); - - int x = p.mCurrentX + dx; - int y = b.mCurrentY + dy; - - // Vertical direction: If we have space to move in the vertical - // direction, we show the edge effect when scrolling reaches the edge. - if (mBoundTop != mBoundBottom) { - if (y < mBoundTop) { - mListener.onPull(mBoundTop - y, EdgeView.BOTTOM); - } else if (y > mBoundBottom) { - mListener.onPull(y - mBoundBottom, EdgeView.TOP); - } - } - - y = Utils.clamp(y, mBoundTop, mBoundBottom); - - // Horizontal direction: we show the edge effect when the scrolling - // tries to go left of the first image or go right of the last image. - if (!mHasPrev && x > mBoundRight) { - int pixels = x - mBoundRight; - mListener.onPull(pixels, EdgeView.LEFT); - x = mBoundRight; - } else if (!mHasNext && x < mBoundLeft) { - int pixels = mBoundLeft - x; - mListener.onPull(pixels, EdgeView.RIGHT); - x = mBoundLeft; - } - - startAnimation(x, y, b.mCurrentScale, ANIM_KIND_SCROLL); - } - - public void scrollFilmX(int dx) { - if (!canScroll()) return; - - Box b = mBoxes.get(0); - Platform p = mPlatform; - - // Only allow scrolling when we are not currently in an animation or we - // are in some animation with can be interrupted. - if (b.mAnimationStartTime != NO_ANIMATION) { - switch (b.mAnimationKind) { - case ANIM_KIND_SCROLL: - case ANIM_KIND_FLING: - case ANIM_KIND_FLING_X: - break; - default: - return; - } - } - - int x = p.mCurrentX + dx; - - // Horizontal direction: we show the edge effect when the scrolling - // tries to go left of the first image or go right of the last image. - x -= mPlatform.mDefaultX; - if (!mHasPrev && x > 0) { - mListener.onPull(x, EdgeView.LEFT); - x = 0; - } else if (!mHasNext && x < 0) { - mListener.onPull(-x, EdgeView.RIGHT); - x = 0; - } - x += mPlatform.mDefaultX; - startAnimation(x, b.mCurrentY, b.mCurrentScale, ANIM_KIND_SCROLL); - } - - public void scrollFilmY(int boxIndex, int dy) { - if (!canScroll()) return; - - Box b = mBoxes.get(boxIndex); - int y = b.mCurrentY + dy; - b.doAnimation(y, b.mCurrentScale, ANIM_KIND_SCROLL); - redraw(); - } - - public boolean flingPage(int velocityX, int velocityY) { - Box b = mBoxes.get(0); - Platform p = mPlatform; - - // We only want to do fling when the picture is zoomed-in. - if (viewWiderThanScaledImage(b.mCurrentScale) && - viewTallerThanScaledImage(b.mCurrentScale)) { - return false; - } - - // We only allow flinging in the directions where it won't go over the - // picture. - int edges = getImageAtEdges(); - if ((velocityX > 0 && (edges & IMAGE_AT_LEFT_EDGE) != 0) || - (velocityX < 0 && (edges & IMAGE_AT_RIGHT_EDGE) != 0)) { - velocityX = 0; - } - if ((velocityY > 0 && (edges & IMAGE_AT_TOP_EDGE) != 0) || - (velocityY < 0 && (edges & IMAGE_AT_BOTTOM_EDGE) != 0)) { - velocityY = 0; - } - - if (velocityX == 0 && velocityY == 0) return false; - - mPageScroller.fling(p.mCurrentX, b.mCurrentY, velocityX, velocityY, - mBoundLeft, mBoundRight, mBoundTop, mBoundBottom); - int targetX = mPageScroller.getFinalX(); - int targetY = mPageScroller.getFinalY(); - ANIM_TIME[ANIM_KIND_FLING] = mPageScroller.getDuration(); - return startAnimation(targetX, targetY, b.mCurrentScale, ANIM_KIND_FLING); - } - - public boolean flingFilmX(int velocityX) { - if (velocityX == 0) return false; - - Box b = mBoxes.get(0); - Platform p = mPlatform; - - // If we are already at the edge, don't start the fling. - int defaultX = p.mDefaultX; - if ((!mHasPrev && p.mCurrentX >= defaultX) - || (!mHasNext && p.mCurrentX <= defaultX)) { - return false; - } - - mFilmScroller.fling(p.mCurrentX, 0, velocityX, 0, - Integer.MIN_VALUE, Integer.MAX_VALUE, 0, 0); - int targetX = mFilmScroller.getFinalX(); - return startAnimation( - targetX, b.mCurrentY, b.mCurrentScale, ANIM_KIND_FLING_X); - } - - // Moves the specified box out of screen. If velocityY is 0, a default - // velocity is used. Returns the time for the duration, or -1 if we cannot - // not do the animation. - public int flingFilmY(int boxIndex, int velocityY) { - Box b = mBoxes.get(boxIndex); - - // Calculate targetY - int h = heightOf(b); - int targetY; - int FUZZY = 3; // TODO: figure out why this is needed. - if (velocityY < 0 || (velocityY == 0 && b.mCurrentY <= 0)) { - targetY = -mViewH / 2 - (h + 1) / 2 - FUZZY; - } else { - targetY = (mViewH + 1) / 2 + h / 2 + FUZZY; - } - - // Calculate duration - int duration; - if (velocityY != 0) { - duration = (int) (Math.abs(targetY - b.mCurrentY) * 1000f - / Math.abs(velocityY)); - duration = Math.min(MAX_DELETE_ANIMATION_DURATION, duration); - } else { - duration = DEFAULT_DELETE_ANIMATION_DURATION; - } - - // Start animation - ANIM_TIME[ANIM_KIND_DELETE] = duration; - if (b.doAnimation(targetY, b.mCurrentScale, ANIM_KIND_DELETE)) { - redraw(); - return duration; - } - return -1; - } - - // Returns the index of the box which contains the given point (x, y) - // Returns Integer.MAX_VALUE if there is no hit. There may be more than - // one box contains the given point, and we want to give priority to the - // one closer to the focused index (0). - public int hitTest(int x, int y) { - for (int i = 0; i < 2 * BOX_MAX + 1; i++) { - int j = CENTER_OUT_INDEX[i]; - Rect r = mRects.get(j); - if (r.contains(x, y)) { - return j; - } - } - - return Integer.MAX_VALUE; - } - - //////////////////////////////////////////////////////////////////////////// - // Redraw - // - // If a method changes box positions directly, redraw() - // should be called. - // - // If a method may also cause a snapback to happen, snapAndRedraw() should - // be called. - // - // If a method starts an animation to change the position of focused box, - // startAnimation() should be called. - // - // If time advances to change the box position, advanceAnimation() should - // be called. - //////////////////////////////////////////////////////////////////////////// - private void redraw() { - layoutAndSetPosition(); - mListener.invalidate(); - } - - private void snapAndRedraw() { - mPlatform.startSnapback(); - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - mBoxes.get(i).startSnapback(); - } - for (int i = -BOX_MAX; i < BOX_MAX; i++) { - mGaps.get(i).startSnapback(); - } - mFilmRatio.startSnapback(); - redraw(); - } - - private boolean startAnimation(int targetX, int targetY, float targetScale, - int kind) { - boolean changed = false; - changed |= mPlatform.doAnimation(targetX, mPlatform.mDefaultY, kind); - changed |= mBoxes.get(0).doAnimation(targetY, targetScale, kind); - if (changed) redraw(); - return changed; - } - - public void advanceAnimation() { - boolean changed = false; - changed |= mPlatform.advanceAnimation(); - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - changed |= mBoxes.get(i).advanceAnimation(); - } - for (int i = -BOX_MAX; i < BOX_MAX; i++) { - changed |= mGaps.get(i).advanceAnimation(); - } - changed |= mFilmRatio.advanceAnimation(); - if (changed) redraw(); - } - - public boolean inOpeningAnimation() { - return (mPlatform.mAnimationKind == ANIM_KIND_OPENING && - mPlatform.mAnimationStartTime != NO_ANIMATION) || - (mBoxes.get(0).mAnimationKind == ANIM_KIND_OPENING && - mBoxes.get(0).mAnimationStartTime != NO_ANIMATION); - } - - //////////////////////////////////////////////////////////////////////////// - // Layout - //////////////////////////////////////////////////////////////////////////// - - // Returns the display width of this box. - private int widthOf(Box b) { - return (int) (b.mImageW * b.mCurrentScale + 0.5f); - } - - // Returns the display height of this box. - private int heightOf(Box b) { - return (int) (b.mImageH * b.mCurrentScale + 0.5f); - } - - // Returns the display width of this box, using the given scale. - private int widthOf(Box b, float scale) { - return (int) (b.mImageW * scale + 0.5f); - } - - // Returns the display height of this box, using the given scale. - private int heightOf(Box b, float scale) { - return (int) (b.mImageH * scale + 0.5f); - } - - // Convert the information in mPlatform and mBoxes to mRects, so the user - // can get the position of each box by getPosition(). - // - // Note we go from center-out because each box's X coordinate - // is relative to its anchor box (except the focused box). - private void layoutAndSetPosition() { - for (int i = 0; i < 2 * BOX_MAX + 1; i++) { - convertBoxToRect(CENTER_OUT_INDEX[i]); - } - //dumpState(); - } - - @SuppressWarnings("unused") - private void dumpState() { - for (int i = -BOX_MAX; i < BOX_MAX; i++) { - Log.d(TAG, "Gap " + i + ": " + mGaps.get(i).mCurrentGap); - } - - for (int i = 0; i < 2 * BOX_MAX + 1; i++) { - dumpRect(CENTER_OUT_INDEX[i]); - } - - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - for (int j = i + 1; j <= BOX_MAX; j++) { - if (Rect.intersects(mRects.get(i), mRects.get(j))) { - Log.d(TAG, "rect " + i + " and rect " + j + "intersects!"); - } - } - } - } - - private void dumpRect(int i) { - StringBuilder sb = new StringBuilder(); - Rect r = mRects.get(i); - sb.append("Rect " + i + ":"); - sb.append("("); - sb.append(r.centerX()); - sb.append(","); - sb.append(r.centerY()); - sb.append(") ["); - sb.append(r.width()); - sb.append("x"); - sb.append(r.height()); - sb.append("]"); - Log.d(TAG, sb.toString()); - } - - private void convertBoxToRect(int i) { - Box b = mBoxes.get(i); - Rect r = mRects.get(i); - int y = b.mCurrentY + mPlatform.mCurrentY + mViewH / 2; - int w = widthOf(b); - int h = heightOf(b); - if (i == 0) { - int x = mPlatform.mCurrentX + mViewW / 2; - r.left = x - w / 2; - r.right = r.left + w; - } else if (i > 0) { - Rect a = mRects.get(i - 1); - Gap g = mGaps.get(i - 1); - r.left = a.right + g.mCurrentGap; - r.right = r.left + w; - } else { // i < 0 - Rect a = mRects.get(i + 1); - Gap g = mGaps.get(i); - r.right = a.left - g.mCurrentGap; - r.left = r.right - w; - } - r.top = y - h / 2; - r.bottom = r.top + h; - } - - // Returns the position of a box. - public Rect getPosition(int index) { - return mRects.get(index); - } - - //////////////////////////////////////////////////////////////////////////// - // Box management - //////////////////////////////////////////////////////////////////////////// - - // Initialize the platform to be at the view center. - private void initPlatform() { - mPlatform.updateDefaultXY(); - mPlatform.mCurrentX = mPlatform.mDefaultX; - mPlatform.mCurrentY = mPlatform.mDefaultY; - mPlatform.mAnimationStartTime = NO_ANIMATION; - } - - // Initialize a box to have the size of the view. - private void initBox(int index) { - Box b = mBoxes.get(index); - b.mImageW = mViewW; - b.mImageH = mViewH; - b.mUseViewSize = true; - b.mScaleMin = getMinimalScale(b); - b.mScaleMax = getMaximalScale(b); - b.mCurrentY = 0; - b.mCurrentScale = b.mScaleMin; - b.mAnimationStartTime = NO_ANIMATION; - b.mAnimationKind = ANIM_KIND_NONE; - } - - // Initialize a box to a given size. - private void initBox(int index, Size size) { - if (size.width == 0 || size.height == 0) { - initBox(index); - return; - } - Box b = mBoxes.get(index); - b.mImageW = size.width; - b.mImageH = size.height; - b.mUseViewSize = false; - b.mScaleMin = getMinimalScale(b); - b.mScaleMax = getMaximalScale(b); - b.mCurrentY = 0; - b.mCurrentScale = b.mScaleMin; - b.mAnimationStartTime = NO_ANIMATION; - b.mAnimationKind = ANIM_KIND_NONE; - } - - // Initialize a gap. This can only be called after the boxes around the gap - // has been initialized. - private void initGap(int index) { - Gap g = mGaps.get(index); - g.mDefaultSize = getDefaultGapSize(index); - g.mCurrentGap = g.mDefaultSize; - g.mAnimationStartTime = NO_ANIMATION; - } - - private void initGap(int index, int size) { - Gap g = mGaps.get(index); - g.mDefaultSize = getDefaultGapSize(index); - g.mCurrentGap = size; - g.mAnimationStartTime = NO_ANIMATION; - } - - @SuppressWarnings("unused") - private void debugMoveBox(int fromIndex[]) { - StringBuilder s = new StringBuilder("moveBox:"); - for (int i = 0; i < fromIndex.length; i++) { - int j = fromIndex[i]; - if (j == Integer.MAX_VALUE) { - s.append(" N"); - } else { - s.append(" "); - s.append(fromIndex[i]); - } - } - Log.d(TAG, s.toString()); - } - - // Move the boxes: it may indicate focus change, box deleted, box appearing, - // box reordered, etc. - // - // Each element in the fromIndex array indicates where each box was in the - // old array. If the value is Integer.MAX_VALUE (pictured as N below), it - // means the box is new. - // - // For example: - // N N N N N N N -- all new boxes - // -3 -2 -1 0 1 2 3 -- nothing changed - // -2 -1 0 1 2 3 N -- focus goes to the next box - // N -3 -2 -1 0 1 2 -- focus goes to the previous box - // -3 -2 -1 1 2 3 N -- the focused box was deleted. - // - // hasPrev/hasNext indicates if there are previous/next boxes for the - // focused box. constrained indicates whether the focused box should be put - // into the constrained frame. - public void moveBox(int fromIndex[], boolean hasPrev, boolean hasNext, - boolean constrained, Size[] sizes) { - //debugMoveBox(fromIndex); - mHasPrev = hasPrev; - mHasNext = hasNext; - - RangeIntArray from = new RangeIntArray(fromIndex, -BOX_MAX, BOX_MAX); - - // 1. Get the absolute X coordinates for the boxes. - layoutAndSetPosition(); - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - Box b = mBoxes.get(i); - Rect r = mRects.get(i); - b.mAbsoluteX = r.centerX() - mViewW / 2; - } - - // 2. copy boxes and gaps to temporary storage. - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - mTempBoxes.put(i, mBoxes.get(i)); - mBoxes.put(i, null); - } - for (int i = -BOX_MAX; i < BOX_MAX; i++) { - mTempGaps.put(i, mGaps.get(i)); - mGaps.put(i, null); - } - - // 3. move back boxes that are used in the new array. - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - int j = from.get(i); - if (j == Integer.MAX_VALUE) continue; - mBoxes.put(i, mTempBoxes.get(j)); - mTempBoxes.put(j, null); - } - - // 4. move back gaps if both boxes around it are kept together. - for (int i = -BOX_MAX; i < BOX_MAX; i++) { - int j = from.get(i); - if (j == Integer.MAX_VALUE) continue; - int k = from.get(i + 1); - if (k == Integer.MAX_VALUE) continue; - if (j + 1 == k) { - mGaps.put(i, mTempGaps.get(j)); - mTempGaps.put(j, null); - } - } - - // 5. recycle the boxes that are not used in the new array. - int k = -BOX_MAX; - for (int i = -BOX_MAX; i <= BOX_MAX; i++) { - if (mBoxes.get(i) != null) continue; - while (mTempBoxes.get(k) == null) { - k++; - } - mBoxes.put(i, mTempBoxes.get(k++)); - initBox(i, sizes[i + BOX_MAX]); - } - - // 6. Now give the recycled box a reasonable absolute X position. - // - // First try to find the first and the last box which the absolute X - // position is known. - int first, last; - for (first = -BOX_MAX; first <= BOX_MAX; first++) { - if (from.get(first) != Integer.MAX_VALUE) break; - } - for (last = BOX_MAX; last >= -BOX_MAX; last--) { - if (from.get(last) != Integer.MAX_VALUE) break; - } - // If there is no box has known X position at all, make the focused one - // as known. - if (first > BOX_MAX) { - mBoxes.get(0).mAbsoluteX = mPlatform.mCurrentX; - first = last = 0; - } - // Now for those boxes between first and last, assign their position to - // align to the previous box or the next box with known position. For - // the boxes before first or after last, we will use a new default gap - // size below. - - // Align to the previous box - for (int i = Math.max(0, first + 1); i < last; i++) { - if (from.get(i) != Integer.MAX_VALUE) continue; - Box a = mBoxes.get(i - 1); - Box b = mBoxes.get(i); - int wa = widthOf(a); - int wb = widthOf(b); - b.mAbsoluteX = a.mAbsoluteX + (wa - wa / 2) + wb / 2 - + getDefaultGapSize(i); - if (mPopFromTop) { - b.mCurrentY = -(mViewH / 2 + heightOf(b) / 2); - } else { - b.mCurrentY = (mViewH / 2 + heightOf(b) / 2); - } - } - - // Align to the next box - for (int i = Math.min(-1, last - 1); i > first; i--) { - if (from.get(i) != Integer.MAX_VALUE) continue; - Box a = mBoxes.get(i + 1); - Box b = mBoxes.get(i); - int wa = widthOf(a); - int wb = widthOf(b); - b.mAbsoluteX = a.mAbsoluteX - wa / 2 - (wb - wb / 2) - - getDefaultGapSize(i); - if (mPopFromTop) { - b.mCurrentY = -(mViewH / 2 + heightOf(b) / 2); - } else { - b.mCurrentY = (mViewH / 2 + heightOf(b) / 2); - } - } - - // 7. recycle the gaps that are not used in the new array. - k = -BOX_MAX; - for (int i = -BOX_MAX; i < BOX_MAX; i++) { - if (mGaps.get(i) != null) continue; - while (mTempGaps.get(k) == null) { - k++; - } - mGaps.put(i, mTempGaps.get(k++)); - Box a = mBoxes.get(i); - Box b = mBoxes.get(i + 1); - int wa = widthOf(a); - int wb = widthOf(b); - if (i >= first && i < last) { - int g = b.mAbsoluteX - a.mAbsoluteX - wb / 2 - (wa - wa / 2); - initGap(i, g); - } else { - initGap(i); - } - } - - // 8. calculate the new absolute X coordinates for those box before - // first or after last. - for (int i = first - 1; i >= -BOX_MAX; i--) { - Box a = mBoxes.get(i + 1); - Box b = mBoxes.get(i); - int wa = widthOf(a); - int wb = widthOf(b); - Gap g = mGaps.get(i); - b.mAbsoluteX = a.mAbsoluteX - wa / 2 - (wb - wb / 2) - g.mCurrentGap; - } - - for (int i = last + 1; i <= BOX_MAX; i++) { - Box a = mBoxes.get(i - 1); - Box b = mBoxes.get(i); - int wa = widthOf(a); - int wb = widthOf(b); - Gap g = mGaps.get(i - 1); - b.mAbsoluteX = a.mAbsoluteX + (wa - wa / 2) + wb / 2 + g.mCurrentGap; - } - - // 9. offset the Platform position - int dx = mBoxes.get(0).mAbsoluteX - mPlatform.mCurrentX; - mPlatform.mCurrentX += dx; - mPlatform.mFromX += dx; - mPlatform.mToX += dx; - mPlatform.mFlingOffset += dx; - - if (mConstrained != constrained) { - mConstrained = constrained; - mPlatform.updateDefaultXY(); - updateScaleAndGapLimit(); - } - - snapAndRedraw(); - } - - //////////////////////////////////////////////////////////////////////////// - // Public utilities - //////////////////////////////////////////////////////////////////////////// - - public boolean isAtMinimalScale() { - Box b = mBoxes.get(0); - return isAlmostEqual(b.mCurrentScale, b.mScaleMin); - } - - public boolean isCenter() { - Box b = mBoxes.get(0); - return mPlatform.mCurrentX == mPlatform.mDefaultX - && b.mCurrentY == 0; - } - - public int getImageWidth() { - Box b = mBoxes.get(0); - return b.mImageW; - } - - public int getImageHeight() { - Box b = mBoxes.get(0); - return b.mImageH; - } - - public float getImageScale() { - Box b = mBoxes.get(0); - return b.mCurrentScale; - } - - public int getImageAtEdges() { - Box b = mBoxes.get(0); - Platform p = mPlatform; - calculateStableBound(b.mCurrentScale); - int edges = 0; - if (p.mCurrentX <= mBoundLeft) { - edges |= IMAGE_AT_RIGHT_EDGE; - } - if (p.mCurrentX >= mBoundRight) { - edges |= IMAGE_AT_LEFT_EDGE; - } - if (b.mCurrentY <= mBoundTop) { - edges |= IMAGE_AT_BOTTOM_EDGE; - } - if (b.mCurrentY >= mBoundBottom) { - edges |= IMAGE_AT_TOP_EDGE; - } - return edges; - } - - public boolean isScrolling() { - return mPlatform.mAnimationStartTime != NO_ANIMATION - && mPlatform.mCurrentX != mPlatform.mToX; - } - - public void stopScrolling() { - if (mPlatform.mAnimationStartTime == NO_ANIMATION) return; - if (mFilmMode) mFilmScroller.forceFinished(true); - mPlatform.mFromX = mPlatform.mToX = mPlatform.mCurrentX; - } - - public float getFilmRatio() { - return mFilmRatio.mCurrentRatio; - } - - public void setPopFromTop(boolean top) { - mPopFromTop = top; - } - - public boolean hasDeletingBox() { - for(int i = -BOX_MAX; i <= BOX_MAX; i++) { - if (mBoxes.get(i).mAnimationKind == ANIM_KIND_DELETE) { - return true; - } - } - return false; - } - - //////////////////////////////////////////////////////////////////////////// - // Private utilities - //////////////////////////////////////////////////////////////////////////// - - private float getMinimalScale(Box b) { - float wFactor = 1.0f; - float hFactor = 1.0f; - int viewW, viewH; - - if (!mFilmMode && mConstrained && !mConstrainedFrame.isEmpty() - && b == mBoxes.get(0)) { - viewW = mConstrainedFrame.width(); - viewH = mConstrainedFrame.height(); - } else { - viewW = mViewW; - viewH = mViewH; - } - - if (mFilmMode) { - if (mViewH > mViewW) { // portrait - wFactor = FILM_MODE_PORTRAIT_WIDTH; - hFactor = FILM_MODE_PORTRAIT_HEIGHT; - } else { // landscape - wFactor = FILM_MODE_LANDSCAPE_WIDTH; - hFactor = FILM_MODE_LANDSCAPE_HEIGHT; - } - } - - float s = Math.min(wFactor * viewW / b.mImageW, - hFactor * viewH / b.mImageH); - return Math.min(SCALE_LIMIT, s); - } - - private float getMaximalScale(Box b) { - if (mFilmMode) return getMinimalScale(b); - if (mConstrained && !mConstrainedFrame.isEmpty()) return getMinimalScale(b); - return SCALE_LIMIT; - } - - private static boolean isAlmostEqual(float a, float b) { - float diff = a - b; - return (diff < 0 ? -diff : diff) < 0.02f; - } - - // Calculates the stable region of mPlatform.mCurrentX and - // mBoxes.get(0).mCurrentY, where "stable" means - // - // (1) If the dimension of scaled image >= view dimension, we will not - // see black region outside the image (at that dimension). - // (2) If the dimension of scaled image < view dimension, we will center - // the scaled image. - // - // We might temporarily go out of this stable during user interaction, - // but will "snap back" after user stops interaction. - // - // The results are stored in mBound{Left/Right/Top/Bottom}. - // - // An extra parameter "horizontalSlack" (which has the value of 0 usually) - // is used to extend the stable region by some pixels on each side - // horizontally. - private void calculateStableBound(float scale, int horizontalSlack) { - Box b = mBoxes.get(0); - - // The width and height of the box in number of view pixels - int w = widthOf(b, scale); - int h = heightOf(b, scale); - - // When the edge of the view is aligned with the edge of the box - mBoundLeft = (mViewW + 1) / 2 - (w + 1) / 2 - horizontalSlack; - mBoundRight = w / 2 - mViewW / 2 + horizontalSlack; - mBoundTop = (mViewH + 1) / 2 - (h + 1) / 2; - mBoundBottom = h / 2 - mViewH / 2; - - // If the scaled height is smaller than the view height, - // force it to be in the center. - if (viewTallerThanScaledImage(scale)) { - mBoundTop = mBoundBottom = 0; - } - - // Same for width - if (viewWiderThanScaledImage(scale)) { - mBoundLeft = mBoundRight = mPlatform.mDefaultX; - } - } - - private void calculateStableBound(float scale) { - calculateStableBound(scale, 0); - } - - private boolean viewTallerThanScaledImage(float scale) { - return mViewH >= heightOf(mBoxes.get(0), scale); - } - - private boolean viewWiderThanScaledImage(float scale) { - return mViewW >= widthOf(mBoxes.get(0), scale); - } - - private float getTargetScale(Box b) { - return b.mAnimationStartTime == NO_ANIMATION - ? b.mCurrentScale : b.mToScale; - } - - //////////////////////////////////////////////////////////////////////////// - // Animatable: an thing which can do animation. - //////////////////////////////////////////////////////////////////////////// - private abstract static class Animatable { - public long mAnimationStartTime; - public int mAnimationKind; - public int mAnimationDuration; - - // This should be overridden in subclass to change the animation values - // give the progress value in [0, 1]. - protected abstract boolean interpolate(float progress); - public abstract boolean startSnapback(); - - // Returns true if the animation values changes, so things need to be - // redrawn. - public boolean advanceAnimation() { - if (mAnimationStartTime == NO_ANIMATION) { - return false; - } - if (mAnimationStartTime == LAST_ANIMATION) { - mAnimationStartTime = NO_ANIMATION; - return startSnapback(); - } - - float progress; - if (mAnimationDuration == 0) { - progress = 1; - } else { - long now = AnimationTime.get(); - progress = - (float) (now - mAnimationStartTime) / mAnimationDuration; - } - - if (progress >= 1) { - progress = 1; - } else { - progress = applyInterpolationCurve(mAnimationKind, progress); - } - - boolean done = interpolate(progress); - - if (done) { - mAnimationStartTime = LAST_ANIMATION; - } - - return true; - } - - private static float applyInterpolationCurve(int kind, float progress) { - float f = 1 - progress; - switch (kind) { - case ANIM_KIND_SCROLL: - case ANIM_KIND_FLING: - case ANIM_KIND_FLING_X: - case ANIM_KIND_DELETE: - case ANIM_KIND_CAPTURE: - progress = 1 - f; // linear - break; - case ANIM_KIND_OPENING: - case ANIM_KIND_SCALE: - progress = 1 - f * f; // quadratic - break; - case ANIM_KIND_SNAPBACK: - case ANIM_KIND_ZOOM: - case ANIM_KIND_SLIDE: - progress = 1 - f * f * f * f * f; // x^5 - break; - } - return progress; - } - } - - //////////////////////////////////////////////////////////////////////////// - // Platform: captures the global X/Y movement. - //////////////////////////////////////////////////////////////////////////// - private class Platform extends Animatable { - public int mCurrentX, mFromX, mToX, mDefaultX; - public int mCurrentY, mFromY, mToY, mDefaultY; - public int mFlingOffset; - - @Override - public boolean startSnapback() { - if (mAnimationStartTime != NO_ANIMATION) return false; - if (mAnimationKind == ANIM_KIND_SCROLL - && mListener.isHoldingDown()) return false; - if (mInScale) return false; - - Box b = mBoxes.get(0); - float scaleMin = mExtraScalingRange ? - b.mScaleMin * SCALE_MIN_EXTRA : b.mScaleMin; - float scaleMax = mExtraScalingRange ? - b.mScaleMax * SCALE_MAX_EXTRA : b.mScaleMax; - float scale = Utils.clamp(b.mCurrentScale, scaleMin, scaleMax); - int x = mCurrentX; - int y = mDefaultY; - if (mFilmMode) { - x = mDefaultX; - } else { - calculateStableBound(scale, HORIZONTAL_SLACK); - // If the picture is zoomed-in, we want to keep the focus point - // stay in the same position on screen, so we need to adjust - // target mCurrentX (which is the center of the focused - // box). The position of the focus point on screen (relative the - // the center of the view) is: - // - // mCurrentX + scale * mFocusX = mCurrentX' + scale' * mFocusX - // => mCurrentX' = mCurrentX + (scale - scale') * mFocusX - // - if (!viewWiderThanScaledImage(scale)) { - float scaleDiff = b.mCurrentScale - scale; - x += (int) (mFocusX * scaleDiff + 0.5f); - } - x = Utils.clamp(x, mBoundLeft, mBoundRight); - } - if (mCurrentX != x || mCurrentY != y) { - return doAnimation(x, y, ANIM_KIND_SNAPBACK); - } - return false; - } - - // The updateDefaultXY() should be called whenever these variables - // changes: (1) mConstrained (2) mConstrainedFrame (3) mViewW/H (4) - // mFilmMode - public void updateDefaultXY() { - // We don't check mFilmMode and return 0 for mDefaultX. Because - // otherwise if we decide to leave film mode because we are - // centered, we will immediately back into film mode because we find - // we are not centered. - if (mConstrained && !mConstrainedFrame.isEmpty()) { - mDefaultX = mConstrainedFrame.centerX() - mViewW / 2; - mDefaultY = mFilmMode ? 0 : - mConstrainedFrame.centerY() - mViewH / 2; - } else { - mDefaultX = 0; - mDefaultY = 0; - } - } - - // Starts an animation for the platform. - private boolean doAnimation(int targetX, int targetY, int kind) { - if (mCurrentX == targetX && mCurrentY == targetY) return false; - mAnimationKind = kind; - mFromX = mCurrentX; - mFromY = mCurrentY; - mToX = targetX; - mToY = targetY; - mAnimationStartTime = AnimationTime.startTime(); - mAnimationDuration = ANIM_TIME[kind]; - mFlingOffset = 0; - advanceAnimation(); - return true; - } - - @Override - protected boolean interpolate(float progress) { - if (mAnimationKind == ANIM_KIND_FLING) { - return interpolateFlingPage(progress); - } else if (mAnimationKind == ANIM_KIND_FLING_X) { - return interpolateFlingFilm(progress); - } else { - return interpolateLinear(progress); - } - } - - private boolean interpolateFlingFilm(float progress) { - mFilmScroller.computeScrollOffset(); - mCurrentX = mFilmScroller.getCurrX() + mFlingOffset; - - int dir = EdgeView.INVALID_DIRECTION; - if (mCurrentX < mDefaultX) { - if (!mHasNext) { - dir = EdgeView.RIGHT; - } - } else if (mCurrentX > mDefaultX) { - if (!mHasPrev) { - dir = EdgeView.LEFT; - } - } - if (dir != EdgeView.INVALID_DIRECTION) { - // TODO: restore this onAbsorb call - //int v = (int) (mFilmScroller.getCurrVelocity() + 0.5f); - //mListener.onAbsorb(v, dir); - mFilmScroller.forceFinished(true); - mCurrentX = mDefaultX; - } - return mFilmScroller.isFinished(); - } - - private boolean interpolateFlingPage(float progress) { - mPageScroller.computeScrollOffset(progress); - Box b = mBoxes.get(0); - calculateStableBound(b.mCurrentScale); - - int oldX = mCurrentX; - mCurrentX = mPageScroller.getCurrX(); - - // Check if we hit the edges; show edge effects if we do. - if (oldX > mBoundLeft && mCurrentX == mBoundLeft) { - int v = (int) (-mPageScroller.getCurrVelocityX() + 0.5f); - mListener.onAbsorb(v, EdgeView.RIGHT); - } else if (oldX < mBoundRight && mCurrentX == mBoundRight) { - int v = (int) (mPageScroller.getCurrVelocityX() + 0.5f); - mListener.onAbsorb(v, EdgeView.LEFT); - } - - return progress >= 1; - } - - private boolean interpolateLinear(float progress) { - // Other animations - if (progress >= 1) { - mCurrentX = mToX; - mCurrentY = mToY; - return true; - } else { - if (mAnimationKind == ANIM_KIND_CAPTURE) { - progress = CaptureAnimation.calculateSlide(progress); - } - mCurrentX = (int) (mFromX + progress * (mToX - mFromX)); - mCurrentY = (int) (mFromY + progress * (mToY - mFromY)); - if (mAnimationKind == ANIM_KIND_CAPTURE) { - return false; - } else { - return (mCurrentX == mToX && mCurrentY == mToY); - } - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // Box: represents a rectangular area which shows a picture. - //////////////////////////////////////////////////////////////////////////// - private class Box extends Animatable { - // Size of the bitmap - public int mImageW, mImageH; - - // This is true if we assume the image size is the same as view size - // until we know the actual size of image. This is also used to - // determine if there is an image ready to show. - public boolean mUseViewSize; - - // The minimum and maximum scale we allow for this box. - public float mScaleMin, mScaleMax; - - // The X/Y value indicates where the center of the box is on the view - // coordinate. We always keep the mCurrent{X,Y,Scale} sync with the - // actual values used currently. Note that the X values are implicitly - // defined by Platform and Gaps. - public int mCurrentY, mFromY, mToY; - public float mCurrentScale, mFromScale, mToScale; - - // The absolute X coordinate of the center of the box. This is only used - // during moveBox(). - public int mAbsoluteX; - - @Override - public boolean startSnapback() { - if (mAnimationStartTime != NO_ANIMATION) return false; - if (mAnimationKind == ANIM_KIND_SCROLL - && mListener.isHoldingDown()) return false; - if (mAnimationKind == ANIM_KIND_DELETE - && mListener.isHoldingDelete()) return false; - if (mInScale && this == mBoxes.get(0)) return false; - - int y = mCurrentY; - float scale; - - if (this == mBoxes.get(0)) { - float scaleMin = mExtraScalingRange ? - mScaleMin * SCALE_MIN_EXTRA : mScaleMin; - float scaleMax = mExtraScalingRange ? - mScaleMax * SCALE_MAX_EXTRA : mScaleMax; - scale = Utils.clamp(mCurrentScale, scaleMin, scaleMax); - if (mFilmMode) { - y = 0; - } else { - calculateStableBound(scale, HORIZONTAL_SLACK); - // If the picture is zoomed-in, we want to keep the focus - // point stay in the same position on screen. See the - // comment in Platform.startSnapback for details. - if (!viewTallerThanScaledImage(scale)) { - float scaleDiff = mCurrentScale - scale; - y += (int) (mFocusY * scaleDiff + 0.5f); - } - y = Utils.clamp(y, mBoundTop, mBoundBottom); - } - } else { - y = 0; - scale = mScaleMin; - } - - if (mCurrentY != y || mCurrentScale != scale) { - return doAnimation(y, scale, ANIM_KIND_SNAPBACK); - } - return false; - } - - private boolean doAnimation(int targetY, float targetScale, int kind) { - targetScale = clampScale(targetScale); - - if (mCurrentY == targetY && mCurrentScale == targetScale - && kind != ANIM_KIND_CAPTURE) { - return false; - } - - // Now starts an animation for the box. - mAnimationKind = kind; - mFromY = mCurrentY; - mFromScale = mCurrentScale; - mToY = targetY; - mToScale = targetScale; - mAnimationStartTime = AnimationTime.startTime(); - mAnimationDuration = ANIM_TIME[kind]; - advanceAnimation(); - return true; - } - - // Clamps the input scale to the range that doAnimation() can reach. - public float clampScale(float s) { - return Utils.clamp(s, - SCALE_MIN_EXTRA * mScaleMin, - SCALE_MAX_EXTRA * mScaleMax); - } - - @Override - protected boolean interpolate(float progress) { - if (mAnimationKind == ANIM_KIND_FLING) { - return interpolateFlingPage(progress); - } else { - return interpolateLinear(progress); - } - } - - private boolean interpolateFlingPage(float progress) { - mPageScroller.computeScrollOffset(progress); - calculateStableBound(mCurrentScale); - - int oldY = mCurrentY; - mCurrentY = mPageScroller.getCurrY(); - - // Check if we hit the edges; show edge effects if we do. - if (oldY > mBoundTop && mCurrentY == mBoundTop) { - int v = (int) (-mPageScroller.getCurrVelocityY() + 0.5f); - mListener.onAbsorb(v, EdgeView.BOTTOM); - } else if (oldY < mBoundBottom && mCurrentY == mBoundBottom) { - int v = (int) (mPageScroller.getCurrVelocityY() + 0.5f); - mListener.onAbsorb(v, EdgeView.TOP); - } - - return progress >= 1; - } - - private boolean interpolateLinear(float progress) { - if (progress >= 1) { - mCurrentY = mToY; - mCurrentScale = mToScale; - return true; - } else { - mCurrentY = (int) (mFromY + progress * (mToY - mFromY)); - mCurrentScale = mFromScale + progress * (mToScale - mFromScale); - if (mAnimationKind == ANIM_KIND_CAPTURE) { - float f = CaptureAnimation.calculateScale(progress); - mCurrentScale *= f; - return false; - } else { - return (mCurrentY == mToY && mCurrentScale == mToScale); - } - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // Gap: represents a rectangular area which is between two boxes. - //////////////////////////////////////////////////////////////////////////// - private class Gap extends Animatable { - // The default gap size between two boxes. The value may vary for - // different image size of the boxes and for different modes (page or - // film). - public int mDefaultSize; - - // The gap size between the two boxes. - public int mCurrentGap, mFromGap, mToGap; - - @Override - public boolean startSnapback() { - if (mAnimationStartTime != NO_ANIMATION) return false; - return doAnimation(mDefaultSize, ANIM_KIND_SNAPBACK); - } - - // Starts an animation for a gap. - public boolean doAnimation(int targetSize, int kind) { - if (mCurrentGap == targetSize && kind != ANIM_KIND_CAPTURE) { - return false; - } - mAnimationKind = kind; - mFromGap = mCurrentGap; - mToGap = targetSize; - mAnimationStartTime = AnimationTime.startTime(); - mAnimationDuration = ANIM_TIME[mAnimationKind]; - advanceAnimation(); - return true; - } - - @Override - protected boolean interpolate(float progress) { - if (progress >= 1) { - mCurrentGap = mToGap; - return true; - } else { - mCurrentGap = (int) (mFromGap + progress * (mToGap - mFromGap)); - if (mAnimationKind == ANIM_KIND_CAPTURE) { - float f = CaptureAnimation.calculateScale(progress); - mCurrentGap = (int) (mCurrentGap * f); - return false; - } else { - return (mCurrentGap == mToGap); - } - } - } - } - - //////////////////////////////////////////////////////////////////////////// - // FilmRatio: represents the progress of film mode change. - //////////////////////////////////////////////////////////////////////////// - private class FilmRatio extends Animatable { - // The film ratio: 1 means switching to film mode is complete, 0 means - // switching to page mode is complete. - public float mCurrentRatio, mFromRatio, mToRatio; - - @Override - public boolean startSnapback() { - float target = mFilmMode ? 1f : 0f; - if (target == mToRatio) return false; - return doAnimation(target, ANIM_KIND_SNAPBACK); - } - - // Starts an animation for the film ratio. - private boolean doAnimation(float targetRatio, int kind) { - mAnimationKind = kind; - mFromRatio = mCurrentRatio; - mToRatio = targetRatio; - mAnimationStartTime = AnimationTime.startTime(); - mAnimationDuration = ANIM_TIME[mAnimationKind]; - advanceAnimation(); - return true; - } - - @Override - protected boolean interpolate(float progress) { - if (progress >= 1) { - mCurrentRatio = mToRatio; - return true; - } else { - mCurrentRatio = mFromRatio + progress * (mToRatio - mFromRatio); - return (mCurrentRatio == mToRatio); - } - } - } -} diff --git a/src/com/android/gallery3d/ui/PreparePageFadeoutTexture.java b/src/com/android/gallery3d/ui/PreparePageFadeoutTexture.java deleted file mode 100644 index ce672f211..000000000 --- a/src/com/android/gallery3d/ui/PreparePageFadeoutTexture.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.android.gallery3d.ui; - -import android.os.ConditionVariable; - -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.RawTexture; -import com.android.gallery3d.ui.GLRoot.OnGLIdleListener; - -public class PreparePageFadeoutTexture implements OnGLIdleListener { - private static final long TIMEOUT = 200; - public static final String KEY_FADE_TEXTURE = "fade_texture"; - - private RawTexture mTexture; - private ConditionVariable mResultReady = new ConditionVariable(false); - private boolean mCancelled = false; - private GLView mRootPane; - - public PreparePageFadeoutTexture(GLView rootPane) { - if (rootPane == null) { - mCancelled = true; - return; - } - int w = rootPane.getWidth(); - int h = rootPane.getHeight(); - if (w == 0 || h == 0) { - mCancelled = true; - return; - } - mTexture = new RawTexture(w, h, true); - mRootPane = rootPane; - } - - public boolean isCancelled() { - return mCancelled; - } - - public synchronized RawTexture get() { - if (mCancelled) { - return null; - } else if (mResultReady.block(TIMEOUT)) { - return mTexture; - } else { - mCancelled = true; - return null; - } - } - - @Override - public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) { - if (!mCancelled) { - try { - canvas.beginRenderTarget(mTexture); - mRootPane.render(canvas); - canvas.endRenderTarget(); - } catch (RuntimeException e) { - mTexture = null; - } - } else { - mTexture = null; - } - mResultReady.open(); - return false; - } - - public static void prepareFadeOutTexture(AbstractGalleryActivity activity, - GLView rootPane) { - PreparePageFadeoutTexture task = new PreparePageFadeoutTexture(rootPane); - if (task.isCancelled()) return; - GLRoot root = activity.getGLRoot(); - RawTexture texture = null; - root.unlockRenderThread(); - try { - root.addOnGLIdleListener(task); - texture = task.get(); - } finally { - root.lockRenderThread(); - } - - if (texture == null) { - return; - } - activity.getTransitionStore().put(KEY_FADE_TEXTURE, texture); - } -} diff --git a/src/com/android/gallery3d/ui/ProgressSpinner.java b/src/com/android/gallery3d/ui/ProgressSpinner.java deleted file mode 100644 index 1b31af278..000000000 --- a/src/com/android/gallery3d/ui/ProgressSpinner.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; - -import com.android.gallery3d.R; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.ResourceTexture; - -public class ProgressSpinner { - private static float ROTATE_SPEED_OUTER = 1080f / 3500f; - private static float ROTATE_SPEED_INNER = -720f / 3500f; - private final ResourceTexture mOuter; - private final ResourceTexture mInner; - private final int mWidth; - private final int mHeight; - - private float mInnerDegree = 0f; - private float mOuterDegree = 0f; - private long mAnimationTimestamp = -1; - - public ProgressSpinner(Context context) { - mOuter = new ResourceTexture(context, R.drawable.spinner_76_outer_holo); - mInner = new ResourceTexture(context, R.drawable.spinner_76_inner_holo); - - mWidth = Math.max(mOuter.getWidth(), mInner.getWidth()); - mHeight = Math.max(mOuter.getHeight(), mInner.getHeight()); - } - - public int getWidth() { - return mWidth; - } - - public int getHeight() { - return mHeight; - } - - public void startAnimation() { - mAnimationTimestamp = -1; - mOuterDegree = 0; - mInnerDegree = 0; - } - - public void draw(GLCanvas canvas, int x, int y) { - long now = AnimationTime.get(); - if (mAnimationTimestamp == -1) mAnimationTimestamp = now; - mOuterDegree += (now - mAnimationTimestamp) * ROTATE_SPEED_OUTER; - mInnerDegree += (now - mAnimationTimestamp) * ROTATE_SPEED_INNER; - - mAnimationTimestamp = now; - - // just preventing overflow - if (mOuterDegree > 360) mOuterDegree -= 360f; - if (mInnerDegree < 0) mInnerDegree += 360f; - - canvas.save(GLCanvas.SAVE_FLAG_MATRIX); - - canvas.translate(x + mWidth / 2, y + mHeight / 2); - canvas.rotate(mInnerDegree, 0, 0, 1); - mOuter.draw(canvas, -mOuter.getWidth() / 2, -mOuter.getHeight() / 2); - canvas.rotate(mOuterDegree - mInnerDegree, 0, 0, 1); - mInner.draw(canvas, -mInner.getWidth() / 2, -mInner.getHeight() / 2); - canvas.restore(); - } -} diff --git a/src/com/android/gallery3d/ui/RelativePosition.java b/src/com/android/gallery3d/ui/RelativePosition.java deleted file mode 100644 index 0f2bfd812..000000000 --- a/src/com/android/gallery3d/ui/RelativePosition.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * 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.ui; - -public class RelativePosition { - private float mAbsoluteX; - private float mAbsoluteY; - private float mReferenceX; - private float mReferenceY; - - public void setAbsolutePosition(int absoluteX, int absoluteY) { - mAbsoluteX = absoluteX; - mAbsoluteY = absoluteY; - } - - public void setReferencePosition(int x, int y) { - mReferenceX = x; - mReferenceY = y; - } - - public float getX() { - return mAbsoluteX - mReferenceX; - } - - public float getY() { - return mAbsoluteY - mReferenceY; - } -} diff --git a/src/com/android/gallery3d/ui/ScreenNail.java b/src/com/android/gallery3d/ui/ScreenNail.java deleted file mode 100644 index 965bf0b54..000000000 --- a/src/com/android/gallery3d/ui/ScreenNail.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.graphics.RectF; - -import com.android.gallery3d.glrenderer.GLCanvas; - -public interface ScreenNail { - public int getWidth(); - public int getHeight(); - public void draw(GLCanvas canvas, int x, int y, int width, int height); - - // We do not need to draw this ScreenNail in this frame. - public void noDraw(); - - // This ScreenNail will not be used anymore. Release related resources. - public void recycle(); - - // This is only used by TileImageView to back up the tiles not yet loaded. - public void draw(GLCanvas canvas, RectF source, RectF dest); -} diff --git a/src/com/android/gallery3d/ui/ScrollBarView.java b/src/com/android/gallery3d/ui/ScrollBarView.java deleted file mode 100644 index 34fbcef7a..000000000 --- a/src/com/android/gallery3d/ui/ScrollBarView.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.graphics.Rect; -import android.util.TypedValue; - -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.NinePatchTexture; - -public class ScrollBarView extends GLView { - @SuppressWarnings("unused") - private static final String TAG = "ScrollBarView"; - - private int mBarHeight; - - private int mGripHeight; - private int mGripPosition; // left side of the grip - private int mGripWidth; // zero if the grip is disabled - private int mGivenGripWidth; - - private int mContentPosition; - private int mContentTotal; - - private NinePatchTexture mScrollBarTexture; - - public ScrollBarView(Context context, int gripHeight, int gripWidth) { - TypedValue outValue = new TypedValue(); - context.getTheme().resolveAttribute( - android.R.attr.scrollbarThumbHorizontal, outValue, true); - mScrollBarTexture = new NinePatchTexture( - context, outValue.resourceId); - mGripPosition = 0; - mGripWidth = 0; - mGivenGripWidth = gripWidth; - mGripHeight = gripHeight; - } - - @Override - protected void onLayout( - boolean changed, int left, int top, int right, int bottom) { - if (!changed) return; - mBarHeight = bottom - top; - } - - // The content position is between 0 to "total". The current position is - // in "position". - public void setContentPosition(int position, int total) { - if (position == mContentPosition && total == mContentTotal) { - return; - } - - invalidate(); - - mContentPosition = position; - mContentTotal = total; - - // If the grip cannot move, don't draw it. - if (mContentTotal <= 0) { - mGripPosition = 0; - mGripWidth = 0; - return; - } - - // Map from the content range to scroll bar range. - // - // mContentTotal --> getWidth() - mGripWidth - // mContentPosition --> mGripPosition - mGripWidth = mGivenGripWidth; - float r = (getWidth() - mGripWidth) / (float) mContentTotal; - mGripPosition = Math.round(r * mContentPosition); - } - - @Override - protected void render(GLCanvas canvas) { - super.render(canvas); - if (mGripWidth == 0) return; - Rect b = bounds(); - int y = (mBarHeight - mGripHeight) / 2; - mScrollBarTexture.draw(canvas, mGripPosition, y, mGripWidth, mGripHeight); - } -} diff --git a/src/com/android/gallery3d/ui/ScrollerHelper.java b/src/com/android/gallery3d/ui/ScrollerHelper.java deleted file mode 100644 index aa68d19d9..000000000 --- a/src/com/android/gallery3d/ui/ScrollerHelper.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.view.ViewConfiguration; - -import com.android.gallery3d.common.OverScroller; -import com.android.gallery3d.common.Utils; - -public class ScrollerHelper { - private OverScroller mScroller; - private int mOverflingDistance; - private boolean mOverflingEnabled; - - public ScrollerHelper(Context context) { - mScroller = new OverScroller(context); - ViewConfiguration configuration = ViewConfiguration.get(context); - mOverflingDistance = configuration.getScaledOverflingDistance(); - } - - public void setOverfling(boolean enabled) { - mOverflingEnabled = enabled; - } - - /** - * Call this when you want to know the new location. The position will be - * updated and can be obtained by getPosition(). Returns true if the - * animation is not yet finished. - */ - public boolean advanceAnimation(long currentTimeMillis) { - return mScroller.computeScrollOffset(); - } - - public boolean isFinished() { - return mScroller.isFinished(); - } - - public void forceFinished() { - mScroller.forceFinished(true); - } - - public int getPosition() { - return mScroller.getCurrX(); - } - - public float getCurrVelocity() { - return mScroller.getCurrVelocity(); - } - - public void setPosition(int position) { - mScroller.startScroll( - position, 0, // startX, startY - 0, 0, 0); // dx, dy, duration - - // This forces the scroller to reach the final position. - mScroller.abortAnimation(); - } - - public void fling(int velocity, int min, int max) { - int currX = getPosition(); - mScroller.fling( - currX, 0, // startX, startY - velocity, 0, // velocityX, velocityY - min, max, // minX, maxX - 0, 0, // minY, maxY - mOverflingEnabled ? mOverflingDistance : 0, 0); - } - - // Returns the distance that over the scroll limit. - public int startScroll(int distance, int min, int max) { - int currPosition = mScroller.getCurrX(); - int finalPosition = mScroller.isFinished() ? currPosition : - mScroller.getFinalX(); - int newPosition = Utils.clamp(finalPosition + distance, min, max); - if (newPosition != currPosition) { - mScroller.startScroll( - currPosition, 0, // startX, startY - newPosition - currPosition, 0, 0); // dx, dy, duration - } - return finalPosition + distance - newPosition; - } -} diff --git a/src/com/android/gallery3d/ui/SelectionManager.java b/src/com/android/gallery3d/ui/SelectionManager.java deleted file mode 100644 index be6811bc1..000000000 --- a/src/com/android/gallery3d/ui/SelectionManager.java +++ /dev/null @@ -1,251 +0,0 @@ -/* - * 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.ui; - -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.data.DataManager; -import com.android.gallery3d.data.MediaItem; -import com.android.gallery3d.data.MediaSet; -import com.android.gallery3d.data.Path; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Set; - -public class SelectionManager { - @SuppressWarnings("unused") - private static final String TAG = "SelectionManager"; - - public static final int ENTER_SELECTION_MODE = 1; - public static final int LEAVE_SELECTION_MODE = 2; - public static final int SELECT_ALL_MODE = 3; - - private Set<Path> mClickedSet; - private MediaSet mSourceMediaSet; - private SelectionListener mListener; - private DataManager mDataManager; - private boolean mInverseSelection; - private boolean mIsAlbumSet; - private boolean mInSelectionMode; - private boolean mAutoLeave = true; - private int mTotal; - - public interface SelectionListener { - public void onSelectionModeChange(int mode); - public void onSelectionChange(Path path, boolean selected); - } - - public SelectionManager(AbstractGalleryActivity activity, boolean isAlbumSet) { - mDataManager = activity.getDataManager(); - mClickedSet = new HashSet<Path>(); - mIsAlbumSet = isAlbumSet; - mTotal = -1; - } - - // Whether we will leave selection mode automatically once the number of - // selected items is down to zero. - public void setAutoLeaveSelectionMode(boolean enable) { - mAutoLeave = enable; - } - - public void setSelectionListener(SelectionListener listener) { - mListener = listener; - } - - public void selectAll() { - mInverseSelection = true; - mClickedSet.clear(); - enterSelectionMode(); - if (mListener != null) mListener.onSelectionModeChange(SELECT_ALL_MODE); - } - - public void deSelectAll() { - leaveSelectionMode(); - mInverseSelection = false; - mClickedSet.clear(); - } - - public boolean inSelectAllMode() { - return mInverseSelection; - } - - public boolean inSelectionMode() { - return mInSelectionMode; - } - - public void enterSelectionMode() { - if (mInSelectionMode) return; - - mInSelectionMode = true; - if (mListener != null) mListener.onSelectionModeChange(ENTER_SELECTION_MODE); - } - - public void leaveSelectionMode() { - if (!mInSelectionMode) return; - - mInSelectionMode = false; - mInverseSelection = false; - mClickedSet.clear(); - if (mListener != null) mListener.onSelectionModeChange(LEAVE_SELECTION_MODE); - } - - public boolean isItemSelected(Path itemId) { - return mInverseSelection ^ mClickedSet.contains(itemId); - } - - private int getTotalCount() { - if (mSourceMediaSet == null) return -1; - - if (mTotal < 0) { - mTotal = mIsAlbumSet - ? mSourceMediaSet.getSubMediaSetCount() - : mSourceMediaSet.getMediaItemCount(); - } - return mTotal; - } - - public int getSelectedCount() { - int count = mClickedSet.size(); - if (mInverseSelection) { - count = getTotalCount() - count; - } - return count; - } - - public void toggle(Path path) { - if (mClickedSet.contains(path)) { - mClickedSet.remove(path); - } else { - enterSelectionMode(); - mClickedSet.add(path); - } - - // Convert to inverse selection mode if everything is selected. - int count = getSelectedCount(); - if (count == getTotalCount()) { - selectAll(); - } - - if (mListener != null) mListener.onSelectionChange(path, isItemSelected(path)); - if (count == 0 && mAutoLeave) { - leaveSelectionMode(); - } - } - - private static boolean expandMediaSet(ArrayList<Path> items, MediaSet set, int maxSelection) { - int subCount = set.getSubMediaSetCount(); - for (int i = 0; i < subCount; i++) { - if (!expandMediaSet(items, set.getSubMediaSet(i), maxSelection)) { - return false; - } - } - int total = set.getMediaItemCount(); - int batch = 50; - int index = 0; - - while (index < total) { - int count = index + batch < total - ? batch - : total - index; - ArrayList<MediaItem> list = set.getMediaItem(index, count); - if (list != null - && list.size() > (maxSelection - items.size())) { - return false; - } - for (MediaItem item : list) { - items.add(item.getPath()); - } - index += batch; - } - return true; - } - - public ArrayList<Path> getSelected(boolean expandSet) { - return getSelected(expandSet, Integer.MAX_VALUE); - } - - public ArrayList<Path> getSelected(boolean expandSet, int maxSelection) { - ArrayList<Path> selected = new ArrayList<Path>(); - if (mIsAlbumSet) { - if (mInverseSelection) { - int total = getTotalCount(); - for (int i = 0; i < total; i++) { - MediaSet set = mSourceMediaSet.getSubMediaSet(i); - Path id = set.getPath(); - if (!mClickedSet.contains(id)) { - if (expandSet) { - if (!expandMediaSet(selected, set, maxSelection)) { - return null; - } - } else { - selected.add(id); - if (selected.size() > maxSelection) { - return null; - } - } - } - } - } else { - for (Path id : mClickedSet) { - if (expandSet) { - if (!expandMediaSet(selected, mDataManager.getMediaSet(id), - maxSelection)) { - return null; - } - } else { - selected.add(id); - if (selected.size() > maxSelection) { - return null; - } - } - } - } - } else { - if (mInverseSelection) { - int total = getTotalCount(); - int index = 0; - while (index < total) { - int count = Math.min(total - index, MediaSet.MEDIAITEM_BATCH_FETCH_COUNT); - ArrayList<MediaItem> list = mSourceMediaSet.getMediaItem(index, count); - for (MediaItem item : list) { - Path id = item.getPath(); - if (!mClickedSet.contains(id)) { - selected.add(id); - if (selected.size() > maxSelection) { - return null; - } - } - } - index += count; - } - } else { - for (Path id : mClickedSet) { - selected.add(id); - if (selected.size() > maxSelection) { - return null; - } - } - } - } - return selected; - } - - public void setSourceMediaSet(MediaSet set) { - mSourceMediaSet = set; - mTotal = -1; - } -} diff --git a/src/com/android/gallery3d/ui/SelectionMenu.java b/src/com/android/gallery3d/ui/SelectionMenu.java deleted file mode 100644 index 5b0828328..000000000 --- a/src/com/android/gallery3d/ui/SelectionMenu.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.view.View; -import android.view.View.OnClickListener; -import android.widget.Button; - -import com.android.gallery3d.R; -import com.android.gallery3d.ui.PopupList.OnPopupItemClickListener; - -public class SelectionMenu implements OnClickListener { - @SuppressWarnings("unused") - private static final String TAG = "SelectionMenu"; - - private final Context mContext; - private final Button mButton; - private final PopupList mPopupList; - - public SelectionMenu(Context context, Button button, OnPopupItemClickListener listener) { - mContext = context; - mButton = button; - mPopupList = new PopupList(context, mButton); - mPopupList.addItem(R.id.action_select_all, - context.getString(R.string.select_all)); - mPopupList.setOnPopupItemClickListener(listener); - mButton.setOnClickListener(this); - } - - @Override - public void onClick(View v) { - mPopupList.show(); - } - - public void updateSelectAllMode(boolean inSelectAllMode) { - PopupList.Item item = mPopupList.findItem(R.id.action_select_all); - if (item != null) { - item.setTitle(mContext.getString( - inSelectAllMode ? R.string.deselect_all : R.string.select_all)); - } - } - - public void setTitle(CharSequence title) { - mButton.setText(title); - } -} diff --git a/src/com/android/gallery3d/ui/SlideshowView.java b/src/com/android/gallery3d/ui/SlideshowView.java deleted file mode 100644 index 43784232d..000000000 --- a/src/com/android/gallery3d/ui/SlideshowView.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * 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.ui; - -import android.graphics.Bitmap; -import android.graphics.PointF; - -import com.android.gallery3d.anim.CanvasAnimation; -import com.android.gallery3d.anim.FloatAnimation; -import com.android.gallery3d.glrenderer.BitmapTexture; -import com.android.gallery3d.glrenderer.GLCanvas; - -import java.util.Random; - -public class SlideshowView extends GLView { - @SuppressWarnings("unused") - private static final String TAG = "SlideshowView"; - - private static final int SLIDESHOW_DURATION = 3500; - private static final int TRANSITION_DURATION = 1000; - - private static final float SCALE_SPEED = 0.20f ; - private static final float MOVE_SPEED = SCALE_SPEED; - - private int mCurrentRotation; - private BitmapTexture mCurrentTexture; - private SlideshowAnimation mCurrentAnimation; - - private int mPrevRotation; - private BitmapTexture mPrevTexture; - private SlideshowAnimation mPrevAnimation; - - private final FloatAnimation mTransitionAnimation = - new FloatAnimation(0, 1, TRANSITION_DURATION); - - private Random mRandom = new Random(); - - public void next(Bitmap bitmap, int rotation) { - - mTransitionAnimation.start(); - - if (mPrevTexture != null) { - mPrevTexture.getBitmap().recycle(); - mPrevTexture.recycle(); - } - - mPrevTexture = mCurrentTexture; - mPrevAnimation = mCurrentAnimation; - mPrevRotation = mCurrentRotation; - - mCurrentRotation = rotation; - mCurrentTexture = new BitmapTexture(bitmap); - if (((rotation / 90) & 0x01) == 0) { - mCurrentAnimation = new SlideshowAnimation( - mCurrentTexture.getWidth(), mCurrentTexture.getHeight(), - mRandom); - } else { - mCurrentAnimation = new SlideshowAnimation( - mCurrentTexture.getHeight(), mCurrentTexture.getWidth(), - mRandom); - } - mCurrentAnimation.start(); - - invalidate(); - } - - public void release() { - if (mPrevTexture != null) { - mPrevTexture.recycle(); - mPrevTexture = null; - } - if (mCurrentTexture != null) { - mCurrentTexture.recycle(); - mCurrentTexture = null; - } - } - - @Override - protected void render(GLCanvas canvas) { - long animTime = AnimationTime.get(); - boolean requestRender = mTransitionAnimation.calculate(animTime); - float alpha = mPrevTexture == null ? 1f : mTransitionAnimation.get(); - - if (mPrevTexture != null && alpha != 1f) { - requestRender |= mPrevAnimation.calculate(animTime); - canvas.save(GLCanvas.SAVE_FLAG_ALPHA | GLCanvas.SAVE_FLAG_MATRIX); - canvas.setAlpha(1f - alpha); - mPrevAnimation.apply(canvas); - canvas.rotate(mPrevRotation, 0, 0, 1); - mPrevTexture.draw(canvas, -mPrevTexture.getWidth() / 2, - -mPrevTexture.getHeight() / 2); - canvas.restore(); - } - if (mCurrentTexture != null) { - requestRender |= mCurrentAnimation.calculate(animTime); - canvas.save(GLCanvas.SAVE_FLAG_ALPHA | GLCanvas.SAVE_FLAG_MATRIX); - canvas.setAlpha(alpha); - mCurrentAnimation.apply(canvas); - canvas.rotate(mCurrentRotation, 0, 0, 1); - mCurrentTexture.draw(canvas, -mCurrentTexture.getWidth() / 2, - -mCurrentTexture.getHeight() / 2); - canvas.restore(); - } - if (requestRender) invalidate(); - } - - private class SlideshowAnimation extends CanvasAnimation { - private final int mWidth; - private final int mHeight; - - private final PointF mMovingVector; - private float mProgress; - - public SlideshowAnimation(int width, int height, Random random) { - mWidth = width; - mHeight = height; - mMovingVector = new PointF( - MOVE_SPEED * mWidth * (random.nextFloat() - 0.5f), - MOVE_SPEED * mHeight * (random.nextFloat() - 0.5f)); - setDuration(SLIDESHOW_DURATION); - } - - @Override - public void apply(GLCanvas canvas) { - int viewWidth = getWidth(); - int viewHeight = getHeight(); - - float initScale = Math.min((float) - viewWidth / mWidth, (float) viewHeight / mHeight); - float scale = initScale * (1 + SCALE_SPEED * mProgress); - - float centerX = viewWidth / 2 + mMovingVector.x * mProgress; - float centerY = viewHeight / 2 + mMovingVector.y * mProgress; - - canvas.translate(centerX, centerY); - canvas.scale(scale, scale, 0); - } - - @Override - public int getCanvasSaveFlags() { - return GLCanvas.SAVE_FLAG_MATRIX; - } - - @Override - protected void onCalculate(float progress) { - mProgress = progress; - } - } -} diff --git a/src/com/android/gallery3d/ui/SlotView.java b/src/com/android/gallery3d/ui/SlotView.java deleted file mode 100644 index bd0ffdc15..000000000 --- a/src/com/android/gallery3d/ui/SlotView.java +++ /dev/null @@ -1,788 +0,0 @@ -/* - * 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.ui; - -import android.graphics.Rect; -import android.os.Handler; -import android.view.GestureDetector; -import android.view.MotionEvent; -import android.view.animation.DecelerateInterpolator; - -import com.android.gallery3d.anim.Animation; -import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.glrenderer.GLCanvas; - -public class SlotView extends GLView { - @SuppressWarnings("unused") - private static final String TAG = "SlotView"; - - private static final boolean WIDE = true; - private static final int INDEX_NONE = -1; - - public static final int RENDER_MORE_PASS = 1; - public static final int RENDER_MORE_FRAME = 2; - - public interface Listener { - public void onDown(int index); - public void onUp(boolean followedByLongPress); - public void onSingleTapUp(int index); - public void onLongTap(int index); - public void onScrollPositionChanged(int position, int total); - } - - public static class SimpleListener implements Listener { - @Override public void onDown(int index) {} - @Override public void onUp(boolean followedByLongPress) {} - @Override public void onSingleTapUp(int index) {} - @Override public void onLongTap(int index) {} - @Override public void onScrollPositionChanged(int position, int total) {} - } - - public static interface SlotRenderer { - public void prepareDrawing(); - public void onVisibleRangeChanged(int visibleStart, int visibleEnd); - public void onSlotSizeChanged(int width, int height); - public int renderSlot(GLCanvas canvas, int index, int pass, int width, int height); - } - - private final GestureDetector mGestureDetector; - private final ScrollerHelper mScroller; - private final Paper mPaper = new Paper(); - - private Listener mListener; - private UserInteractionListener mUIListener; - - private boolean mMoreAnimation = false; - private SlotAnimation mAnimation = null; - private final Layout mLayout = new Layout(); - private int mStartIndex = INDEX_NONE; - - // whether the down action happened while the view is scrolling. - private boolean mDownInScrolling; - private int mOverscrollEffect = OVERSCROLL_3D; - private final Handler mHandler; - - private SlotRenderer mRenderer; - - private int[] mRequestRenderSlots = new int[16]; - - public static final int OVERSCROLL_3D = 0; - public static final int OVERSCROLL_SYSTEM = 1; - public static final int OVERSCROLL_NONE = 2; - - // to prevent allocating memory - private final Rect mTempRect = new Rect(); - - public SlotView(AbstractGalleryActivity activity, Spec spec) { - mGestureDetector = new GestureDetector(activity, new MyGestureListener()); - mScroller = new ScrollerHelper(activity); - mHandler = new SynchronizedHandler(activity.getGLRoot()); - setSlotSpec(spec); - } - - public void setSlotRenderer(SlotRenderer slotDrawer) { - mRenderer = slotDrawer; - if (mRenderer != null) { - mRenderer.onSlotSizeChanged(mLayout.mSlotWidth, mLayout.mSlotHeight); - mRenderer.onVisibleRangeChanged(getVisibleStart(), getVisibleEnd()); - } - } - - public void setCenterIndex(int index) { - int slotCount = mLayout.mSlotCount; - if (index < 0 || index >= slotCount) { - return; - } - Rect rect = mLayout.getSlotRect(index, mTempRect); - int position = WIDE - ? (rect.left + rect.right - getWidth()) / 2 - : (rect.top + rect.bottom - getHeight()) / 2; - setScrollPosition(position); - } - - public void makeSlotVisible(int index) { - Rect rect = mLayout.getSlotRect(index, mTempRect); - int visibleBegin = WIDE ? mScrollX : mScrollY; - int visibleLength = WIDE ? getWidth() : getHeight(); - int visibleEnd = visibleBegin + visibleLength; - int slotBegin = WIDE ? rect.left : rect.top; - int slotEnd = WIDE ? rect.right : rect.bottom; - - int position = visibleBegin; - if (visibleLength < slotEnd - slotBegin) { - position = visibleBegin; - } else if (slotBegin < visibleBegin) { - position = slotBegin; - } else if (slotEnd > visibleEnd) { - position = slotEnd - visibleLength; - } - - setScrollPosition(position); - } - - public void setScrollPosition(int position) { - position = Utils.clamp(position, 0, mLayout.getScrollLimit()); - mScroller.setPosition(position); - updateScrollPosition(position, false); - } - - public void setSlotSpec(Spec spec) { - mLayout.setSlotSpec(spec); - } - - @Override - public void addComponent(GLView view) { - throw new UnsupportedOperationException(); - } - - @Override - protected void onLayout(boolean changeSize, int l, int t, int r, int b) { - if (!changeSize) return; - - // Make sure we are still at a resonable scroll position after the size - // is changed (like orientation change). We choose to keep the center - // visible slot still visible. This is arbitrary but reasonable. - int visibleIndex = - (mLayout.getVisibleStart() + mLayout.getVisibleEnd()) / 2; - mLayout.setSize(r - l, b - t); - makeSlotVisible(visibleIndex); - if (mOverscrollEffect == OVERSCROLL_3D) { - mPaper.setSize(r - l, b - t); - } - } - - public void startScatteringAnimation(RelativePosition position) { - mAnimation = new ScatteringAnimation(position); - mAnimation.start(); - if (mLayout.mSlotCount != 0) invalidate(); - } - - public void startRisingAnimation() { - mAnimation = new RisingAnimation(); - mAnimation.start(); - if (mLayout.mSlotCount != 0) invalidate(); - } - - private void updateScrollPosition(int position, boolean force) { - if (!force && (WIDE ? position == mScrollX : position == mScrollY)) return; - if (WIDE) { - mScrollX = position; - } else { - mScrollY = position; - } - mLayout.setScrollPosition(position); - onScrollPositionChanged(position); - } - - protected void onScrollPositionChanged(int newPosition) { - int limit = mLayout.getScrollLimit(); - mListener.onScrollPositionChanged(newPosition, limit); - } - - public Rect getSlotRect(int slotIndex) { - return mLayout.getSlotRect(slotIndex, new Rect()); - } - - @Override - protected boolean onTouch(MotionEvent event) { - if (mUIListener != null) mUIListener.onUserInteraction(); - mGestureDetector.onTouchEvent(event); - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - mDownInScrolling = !mScroller.isFinished(); - mScroller.forceFinished(); - break; - case MotionEvent.ACTION_UP: - mPaper.onRelease(); - invalidate(); - break; - } - return true; - } - - public void setListener(Listener listener) { - mListener = listener; - } - - public void setUserInteractionListener(UserInteractionListener listener) { - mUIListener = listener; - } - - public void setOverscrollEffect(int kind) { - mOverscrollEffect = kind; - mScroller.setOverfling(kind == OVERSCROLL_SYSTEM); - } - - private static int[] expandIntArray(int array[], int capacity) { - while (array.length < capacity) { - array = new int[array.length * 2]; - } - return array; - } - - @Override - protected void render(GLCanvas canvas) { - super.render(canvas); - - if (mRenderer == null) return; - mRenderer.prepareDrawing(); - - long animTime = AnimationTime.get(); - boolean more = mScroller.advanceAnimation(animTime); - more |= mLayout.advanceAnimation(animTime); - int oldX = mScrollX; - updateScrollPosition(mScroller.getPosition(), false); - - boolean paperActive = false; - if (mOverscrollEffect == OVERSCROLL_3D) { - // Check if an edge is reached and notify mPaper if so. - int newX = mScrollX; - int limit = mLayout.getScrollLimit(); - if (oldX > 0 && newX == 0 || oldX < limit && newX == limit) { - float v = mScroller.getCurrVelocity(); - if (newX == limit) v = -v; - - // I don't know why, but getCurrVelocity() can return NaN. - if (!Float.isNaN(v)) { - mPaper.edgeReached(v); - } - } - paperActive = mPaper.advanceAnimation(); - } - - more |= paperActive; - - if (mAnimation != null) { - more |= mAnimation.calculate(animTime); - } - - canvas.translate(-mScrollX, -mScrollY); - - int requestCount = 0; - int requestedSlot[] = expandIntArray(mRequestRenderSlots, - mLayout.mVisibleEnd - mLayout.mVisibleStart); - - for (int i = mLayout.mVisibleEnd - 1; i >= mLayout.mVisibleStart; --i) { - int r = renderItem(canvas, i, 0, paperActive); - if ((r & RENDER_MORE_FRAME) != 0) more = true; - if ((r & RENDER_MORE_PASS) != 0) requestedSlot[requestCount++] = i; - } - - for (int pass = 1; requestCount != 0; ++pass) { - int newCount = 0; - for (int i = 0; i < requestCount; ++i) { - int r = renderItem(canvas, - requestedSlot[i], pass, paperActive); - if ((r & RENDER_MORE_FRAME) != 0) more = true; - if ((r & RENDER_MORE_PASS) != 0) requestedSlot[newCount++] = i; - } - requestCount = newCount; - } - - canvas.translate(mScrollX, mScrollY); - - if (more) invalidate(); - - final UserInteractionListener listener = mUIListener; - if (mMoreAnimation && !more && listener != null) { - mHandler.post(new Runnable() { - @Override - public void run() { - listener.onUserInteractionEnd(); - } - }); - } - mMoreAnimation = more; - } - - private int renderItem( - GLCanvas canvas, int index, int pass, boolean paperActive) { - canvas.save(GLCanvas.SAVE_FLAG_ALPHA | GLCanvas.SAVE_FLAG_MATRIX); - Rect rect = mLayout.getSlotRect(index, mTempRect); - if (paperActive) { - canvas.multiplyMatrix(mPaper.getTransform(rect, mScrollX), 0); - } else { - canvas.translate(rect.left, rect.top, 0); - } - if (mAnimation != null && mAnimation.isActive()) { - mAnimation.apply(canvas, index, rect); - } - int result = mRenderer.renderSlot( - canvas, index, pass, rect.right - rect.left, rect.bottom - rect.top); - canvas.restore(); - return result; - } - - public static abstract class SlotAnimation extends Animation { - protected float mProgress = 0; - - public SlotAnimation() { - setInterpolator(new DecelerateInterpolator(4)); - setDuration(1500); - } - - @Override - protected void onCalculate(float progress) { - mProgress = progress; - } - - abstract public void apply(GLCanvas canvas, int slotIndex, Rect target); - } - - public static class RisingAnimation extends SlotAnimation { - private static final int RISING_DISTANCE = 128; - - @Override - public void apply(GLCanvas canvas, int slotIndex, Rect target) { - canvas.translate(0, 0, RISING_DISTANCE * (1 - mProgress)); - } - } - - public static class ScatteringAnimation extends SlotAnimation { - private int PHOTO_DISTANCE = 1000; - private RelativePosition mCenter; - - public ScatteringAnimation(RelativePosition center) { - mCenter = center; - } - - @Override - public void apply(GLCanvas canvas, int slotIndex, Rect target) { - canvas.translate( - (mCenter.getX() - target.centerX()) * (1 - mProgress), - (mCenter.getY() - target.centerY()) * (1 - mProgress), - slotIndex * PHOTO_DISTANCE * (1 - mProgress)); - canvas.setAlpha(mProgress); - } - } - - // This Spec class is used to specify the size of each slot in the SlotView. - // There are two ways to do it: - // - // (1) Specify slotWidth and slotHeight: they specify the width and height - // of each slot. The number of rows and the gap between slots will be - // determined automatically. - // (2) Specify rowsLand, rowsPort, and slotGap: they specify the number - // of rows in landscape/portrait mode and the gap between slots. The - // width and height of each slot is determined automatically. - // - // The initial value of -1 means they are not specified. - public static class Spec { - public int slotWidth = -1; - public int slotHeight = -1; - public int slotHeightAdditional = 0; - - public int rowsLand = -1; - public int rowsPort = -1; - public int slotGap = -1; - } - - public class Layout { - - private int mVisibleStart; - private int mVisibleEnd; - - private int mSlotCount; - private int mSlotWidth; - private int mSlotHeight; - private int mSlotGap; - - private Spec mSpec; - - private int mWidth; - private int mHeight; - - private int mUnitCount; - private int mContentLength; - private int mScrollPosition; - - private IntegerAnimation mVerticalPadding = new IntegerAnimation(); - private IntegerAnimation mHorizontalPadding = new IntegerAnimation(); - - public void setSlotSpec(Spec spec) { - mSpec = spec; - } - - public boolean setSlotCount(int slotCount) { - if (slotCount == mSlotCount) return false; - if (mSlotCount != 0) { - mHorizontalPadding.setEnabled(true); - mVerticalPadding.setEnabled(true); - } - mSlotCount = slotCount; - int hPadding = mHorizontalPadding.getTarget(); - int vPadding = mVerticalPadding.getTarget(); - initLayoutParameters(); - return vPadding != mVerticalPadding.getTarget() - || hPadding != mHorizontalPadding.getTarget(); - } - - public Rect getSlotRect(int index, Rect rect) { - int col, row; - if (WIDE) { - col = index / mUnitCount; - row = index - col * mUnitCount; - } else { - row = index / mUnitCount; - col = index - row * mUnitCount; - } - - int x = mHorizontalPadding.get() + col * (mSlotWidth + mSlotGap); - int y = mVerticalPadding.get() + row * (mSlotHeight + mSlotGap); - rect.set(x, y, x + mSlotWidth, y + mSlotHeight); - return rect; - } - - public int getSlotWidth() { - return mSlotWidth; - } - - public int getSlotHeight() { - return mSlotHeight; - } - - // Calculate - // (1) mUnitCount: the number of slots we can fit into one column (or row). - // (2) mContentLength: the width (or height) we need to display all the - // columns (rows). - // (3) padding[]: the vertical and horizontal padding we need in order - // to put the slots towards to the center of the display. - // - // The "major" direction is the direction the user can scroll. The other - // direction is the "minor" direction. - // - // The comments inside this method are the description when the major - // directon is horizontal (X), and the minor directon is vertical (Y). - private void initLayoutParameters( - int majorLength, int minorLength, /* The view width and height */ - int majorUnitSize, int minorUnitSize, /* The slot width and height */ - int[] padding) { - int unitCount = (minorLength + mSlotGap) / (minorUnitSize + mSlotGap); - if (unitCount == 0) unitCount = 1; - mUnitCount = unitCount; - - // We put extra padding above and below the column. - int availableUnits = Math.min(mUnitCount, mSlotCount); - int usedMinorLength = availableUnits * minorUnitSize + - (availableUnits - 1) * mSlotGap; - padding[0] = (minorLength - usedMinorLength) / 2; - - // Then calculate how many columns we need for all slots. - int count = ((mSlotCount + mUnitCount - 1) / mUnitCount); - mContentLength = count * majorUnitSize + (count - 1) * mSlotGap; - - // If the content length is less then the screen width, put - // extra padding in left and right. - padding[1] = Math.max(0, (majorLength - mContentLength) / 2); - } - - private void initLayoutParameters() { - // Initialize mSlotWidth and mSlotHeight from mSpec - if (mSpec.slotWidth != -1) { - mSlotGap = 0; - mSlotWidth = mSpec.slotWidth; - mSlotHeight = mSpec.slotHeight; - } else { - int rows = (mWidth > mHeight) ? mSpec.rowsLand : mSpec.rowsPort; - mSlotGap = mSpec.slotGap; - mSlotHeight = Math.max(1, (mHeight - (rows - 1) * mSlotGap) / rows); - mSlotWidth = mSlotHeight - mSpec.slotHeightAdditional; - } - - if (mRenderer != null) { - mRenderer.onSlotSizeChanged(mSlotWidth, mSlotHeight); - } - - int[] padding = new int[2]; - if (WIDE) { - initLayoutParameters(mWidth, mHeight, mSlotWidth, mSlotHeight, padding); - mVerticalPadding.startAnimateTo(padding[0]); - mHorizontalPadding.startAnimateTo(padding[1]); - } else { - initLayoutParameters(mHeight, mWidth, mSlotHeight, mSlotWidth, padding); - mVerticalPadding.startAnimateTo(padding[1]); - mHorizontalPadding.startAnimateTo(padding[0]); - } - updateVisibleSlotRange(); - } - - public void setSize(int width, int height) { - mWidth = width; - mHeight = height; - initLayoutParameters(); - } - - private void updateVisibleSlotRange() { - int position = mScrollPosition; - - if (WIDE) { - int startCol = position / (mSlotWidth + mSlotGap); - int start = Math.max(0, mUnitCount * startCol); - int endCol = (position + mWidth + mSlotWidth + mSlotGap - 1) / - (mSlotWidth + mSlotGap); - int end = Math.min(mSlotCount, mUnitCount * endCol); - setVisibleRange(start, end); - } else { - int startRow = position / (mSlotHeight + mSlotGap); - int start = Math.max(0, mUnitCount * startRow); - int endRow = (position + mHeight + mSlotHeight + mSlotGap - 1) / - (mSlotHeight + mSlotGap); - int end = Math.min(mSlotCount, mUnitCount * endRow); - setVisibleRange(start, end); - } - } - - public void setScrollPosition(int position) { - if (mScrollPosition == position) return; - mScrollPosition = position; - updateVisibleSlotRange(); - } - - private void setVisibleRange(int start, int end) { - if (start == mVisibleStart && end == mVisibleEnd) return; - if (start < end) { - mVisibleStart = start; - mVisibleEnd = end; - } else { - mVisibleStart = mVisibleEnd = 0; - } - if (mRenderer != null) { - mRenderer.onVisibleRangeChanged(mVisibleStart, mVisibleEnd); - } - } - - public int getVisibleStart() { - return mVisibleStart; - } - - public int getVisibleEnd() { - return mVisibleEnd; - } - - public int getSlotIndexByPosition(float x, float y) { - int absoluteX = Math.round(x) + (WIDE ? mScrollPosition : 0); - int absoluteY = Math.round(y) + (WIDE ? 0 : mScrollPosition); - - absoluteX -= mHorizontalPadding.get(); - absoluteY -= mVerticalPadding.get(); - - if (absoluteX < 0 || absoluteY < 0) { - return INDEX_NONE; - } - - int columnIdx = absoluteX / (mSlotWidth + mSlotGap); - int rowIdx = absoluteY / (mSlotHeight + mSlotGap); - - if (!WIDE && columnIdx >= mUnitCount) { - return INDEX_NONE; - } - - if (WIDE && rowIdx >= mUnitCount) { - return INDEX_NONE; - } - - if (absoluteX % (mSlotWidth + mSlotGap) >= mSlotWidth) { - return INDEX_NONE; - } - - if (absoluteY % (mSlotHeight + mSlotGap) >= mSlotHeight) { - return INDEX_NONE; - } - - int index = WIDE - ? (columnIdx * mUnitCount + rowIdx) - : (rowIdx * mUnitCount + columnIdx); - - return index >= mSlotCount ? INDEX_NONE : index; - } - - public int getScrollLimit() { - int limit = WIDE ? mContentLength - mWidth : mContentLength - mHeight; - return limit <= 0 ? 0 : limit; - } - - public boolean advanceAnimation(long animTime) { - // use '|' to make sure both sides will be executed - return mVerticalPadding.calculate(animTime) | mHorizontalPadding.calculate(animTime); - } - } - - private class MyGestureListener implements GestureDetector.OnGestureListener { - private boolean isDown; - - // We call the listener's onDown() when our onShowPress() is called and - // call the listener's onUp() when we receive any further event. - @Override - public void onShowPress(MotionEvent e) { - GLRoot root = getGLRoot(); - root.lockRenderThread(); - try { - if (isDown) return; - int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); - if (index != INDEX_NONE) { - isDown = true; - mListener.onDown(index); - } - } finally { - root.unlockRenderThread(); - } - } - - private void cancelDown(boolean byLongPress) { - if (!isDown) return; - isDown = false; - mListener.onUp(byLongPress); - } - - @Override - public boolean onDown(MotionEvent e) { - return false; - } - - @Override - public boolean onFling(MotionEvent e1, - MotionEvent e2, float velocityX, float velocityY) { - cancelDown(false); - int scrollLimit = mLayout.getScrollLimit(); - if (scrollLimit == 0) return false; - float velocity = WIDE ? velocityX : velocityY; - mScroller.fling((int) -velocity, 0, scrollLimit); - if (mUIListener != null) mUIListener.onUserInteractionBegin(); - invalidate(); - return true; - } - - @Override - public boolean onScroll(MotionEvent e1, - MotionEvent e2, float distanceX, float distanceY) { - cancelDown(false); - float distance = WIDE ? distanceX : distanceY; - int overDistance = mScroller.startScroll( - Math.round(distance), 0, mLayout.getScrollLimit()); - if (mOverscrollEffect == OVERSCROLL_3D && overDistance != 0) { - mPaper.overScroll(overDistance); - } - invalidate(); - return true; - } - - @Override - public boolean onSingleTapUp(MotionEvent e) { - cancelDown(false); - if (mDownInScrolling) return true; - int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); - if (index != INDEX_NONE) mListener.onSingleTapUp(index); - return true; - } - - @Override - public void onLongPress(MotionEvent e) { - cancelDown(true); - if (mDownInScrolling) return; - lockRendering(); - try { - int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); - if (index != INDEX_NONE) mListener.onLongTap(index); - } finally { - unlockRendering(); - } - } - } - - public void setStartIndex(int index) { - mStartIndex = index; - } - - // Return true if the layout parameters have been changed - public boolean setSlotCount(int slotCount) { - boolean changed = mLayout.setSlotCount(slotCount); - - // mStartIndex is applied the first time setSlotCount is called. - if (mStartIndex != INDEX_NONE) { - setCenterIndex(mStartIndex); - mStartIndex = INDEX_NONE; - } - // Reset the scroll position to avoid scrolling over the updated limit. - setScrollPosition(WIDE ? mScrollX : mScrollY); - return changed; - } - - public int getVisibleStart() { - return mLayout.getVisibleStart(); - } - - public int getVisibleEnd() { - return mLayout.getVisibleEnd(); - } - - public int getScrollX() { - return mScrollX; - } - - public int getScrollY() { - return mScrollY; - } - - public Rect getSlotRect(int slotIndex, GLView rootPane) { - // Get slot rectangle relative to this root pane. - Rect offset = new Rect(); - rootPane.getBoundsOf(this, offset); - Rect r = getSlotRect(slotIndex); - r.offset(offset.left - getScrollX(), - offset.top - getScrollY()); - return r; - } - - private static class IntegerAnimation extends Animation { - private int mTarget; - private int mCurrent = 0; - private int mFrom = 0; - private boolean mEnabled = false; - - public void setEnabled(boolean enabled) { - mEnabled = enabled; - } - - public void startAnimateTo(int target) { - if (!mEnabled) { - mTarget = mCurrent = target; - return; - } - if (target == mTarget) return; - - mFrom = mCurrent; - mTarget = target; - setDuration(180); - start(); - } - - public int get() { - return mCurrent; - } - - public int getTarget() { - return mTarget; - } - - @Override - protected void onCalculate(float progress) { - mCurrent = Math.round(mFrom + progress * (mTarget - mFrom)); - if (progress == 1f) mEnabled = false; - } - } -} diff --git a/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java b/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java deleted file mode 100644 index 18121e63b..000000000 --- a/src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.annotation.TargetApi; -import android.graphics.RectF; -import android.graphics.SurfaceTexture; - -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.glrenderer.ExtTexture; -import com.android.gallery3d.glrenderer.GLCanvas; - -@TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) -public abstract class SurfaceTextureScreenNail implements ScreenNail, - SurfaceTexture.OnFrameAvailableListener { - @SuppressWarnings("unused") - private static final String TAG = "SurfaceTextureScreenNail"; - // This constant is not available in API level before 15, but it was just an - // oversight. - private static final int GL_TEXTURE_EXTERNAL_OES = 0x8D65; - - protected ExtTexture mExtTexture; - private SurfaceTexture mSurfaceTexture; - private int mWidth, mHeight; - private float[] mTransform = new float[16]; - private boolean mHasTexture = false; - - public SurfaceTextureScreenNail() { - } - - public void acquireSurfaceTexture(GLCanvas canvas) { - mExtTexture = new ExtTexture(canvas, GL_TEXTURE_EXTERNAL_OES); - mExtTexture.setSize(mWidth, mHeight); - mSurfaceTexture = new SurfaceTexture(mExtTexture.getId()); - setDefaultBufferSize(mSurfaceTexture, mWidth, mHeight); - mSurfaceTexture.setOnFrameAvailableListener(this); - synchronized (this) { - mHasTexture = true; - } - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) - private static void setDefaultBufferSize(SurfaceTexture st, int width, int height) { - if (ApiHelper.HAS_SET_DEFALT_BUFFER_SIZE) { - st.setDefaultBufferSize(width, height); - } - } - - @TargetApi(ApiHelper.VERSION_CODES.ICE_CREAM_SANDWICH) - private static void releaseSurfaceTexture(SurfaceTexture st) { - st.setOnFrameAvailableListener(null); - if (ApiHelper.HAS_RELEASE_SURFACE_TEXTURE) { - st.release(); - } - } - - public SurfaceTexture getSurfaceTexture() { - return mSurfaceTexture; - } - - public void releaseSurfaceTexture() { - synchronized (this) { - mHasTexture = false; - } - mExtTexture.recycle(); - mExtTexture = null; - releaseSurfaceTexture(mSurfaceTexture); - mSurfaceTexture = null; - } - - public void setSize(int width, int height) { - mWidth = width; - mHeight = height; - } - - public void resizeTexture() { - if (mExtTexture != null) { - mExtTexture.setSize(mWidth, mHeight); - setDefaultBufferSize(mSurfaceTexture, mWidth, mHeight); - } - } - - @Override - public int getWidth() { - return mWidth; - } - - @Override - public int getHeight() { - return mHeight; - } - - @Override - public void draw(GLCanvas canvas, int x, int y, int width, int height) { - synchronized (this) { - if (!mHasTexture) return; - mSurfaceTexture.updateTexImage(); - mSurfaceTexture.getTransformMatrix(mTransform); - - // Flip vertically. - canvas.save(GLCanvas.SAVE_FLAG_MATRIX); - int cx = x + width / 2; - int cy = y + height / 2; - canvas.translate(cx, cy); - canvas.scale(1, -1, 1); - canvas.translate(-cx, -cy); - updateTransformMatrix(mTransform); - canvas.drawTexture(mExtTexture, mTransform, x, y, width, height); - canvas.restore(); - } - } - - @Override - public void draw(GLCanvas canvas, RectF source, RectF dest) { - throw new UnsupportedOperationException(); - } - - protected void updateTransformMatrix(float[] matrix) {} - - @Override - abstract public void noDraw(); - - @Override - abstract public void recycle(); - - @Override - abstract public void onFrameAvailable(SurfaceTexture surfaceTexture); -} diff --git a/src/com/android/gallery3d/ui/SynchronizedHandler.java b/src/com/android/gallery3d/ui/SynchronizedHandler.java deleted file mode 100644 index ba1035747..000000000 --- a/src/com/android/gallery3d/ui/SynchronizedHandler.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.ui; - -import android.os.Handler; -import android.os.Message; - -import com.android.gallery3d.common.Utils; - -public class SynchronizedHandler extends Handler { - - private final GLRoot mRoot; - - public SynchronizedHandler(GLRoot root) { - mRoot = Utils.checkNotNull(root); - } - - @Override - public void dispatchMessage(Message message) { - mRoot.lockRenderThread(); - try { - super.dispatchMessage(message); - } finally { - mRoot.unlockRenderThread(); - } - } -} diff --git a/src/com/android/gallery3d/ui/TileImageView.java b/src/com/android/gallery3d/ui/TileImageView.java deleted file mode 100644 index 3185c7598..000000000 --- a/src/com/android/gallery3d/ui/TileImageView.java +++ /dev/null @@ -1,786 +0,0 @@ -/* - * 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.ui; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Point; -import android.graphics.Rect; -import android.graphics.RectF; -import android.support.v4.util.LongSparseArray; -import android.util.DisplayMetrics; -import android.util.FloatMath; -import android.view.WindowManager; - -import com.android.gallery3d.app.GalleryContext; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.data.DecodeUtils; -import com.android.photos.data.GalleryBitmapPool; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.UploadedTexture; -import com.android.gallery3d.util.Future; -import com.android.gallery3d.util.ThreadPool; -import com.android.gallery3d.util.ThreadPool.CancelListener; -import com.android.gallery3d.util.ThreadPool.JobContext; - -import java.util.concurrent.atomic.AtomicBoolean; - -public class TileImageView extends GLView { - public static final int SIZE_UNKNOWN = -1; - - @SuppressWarnings("unused") - private static final String TAG = "TileImageView"; - private static final int UPLOAD_LIMIT = 1; - - // TILE_SIZE must be 2^N - private static int sTileSize; - - /* - * This is the tile state in the CPU side. - * Life of a Tile: - * ACTIVATED (initial state) - * --> IN_QUEUE - by queueForDecode() - * --> RECYCLED - by recycleTile() - * IN_QUEUE --> DECODING - by decodeTile() - * --> RECYCLED - by recycleTile) - * DECODING --> RECYCLING - by recycleTile() - * --> DECODED - by decodeTile() - * --> DECODE_FAIL - by decodeTile() - * RECYCLING --> RECYCLED - by decodeTile() - * DECODED --> ACTIVATED - (after the decoded bitmap is uploaded) - * DECODED --> RECYCLED - by recycleTile() - * DECODE_FAIL -> RECYCLED - by recycleTile() - * RECYCLED --> ACTIVATED - by obtainTile() - */ - private static final int STATE_ACTIVATED = 0x01; - private static final int STATE_IN_QUEUE = 0x02; - private static final int STATE_DECODING = 0x04; - private static final int STATE_DECODED = 0x08; - private static final int STATE_DECODE_FAIL = 0x10; - private static final int STATE_RECYCLING = 0x20; - private static final int STATE_RECYCLED = 0x40; - - private TileSource mModel; - private ScreenNail mScreenNail; - protected int mLevelCount; // cache the value of mScaledBitmaps.length - - // The mLevel variable indicates which level of bitmap we should use. - // Level 0 means the original full-sized bitmap, and a larger value means - // a smaller scaled bitmap (The width and height of each scaled bitmap is - // half size of the previous one). If the value is in [0, mLevelCount), we - // use the bitmap in mScaledBitmaps[mLevel] for display, otherwise the value - // is mLevelCount, and that means we use mScreenNail for display. - private int mLevel = 0; - - // The offsets of the (left, top) of the upper-left tile to the (left, top) - // of the view. - private int mOffsetX; - private int mOffsetY; - - private int mUploadQuota; - private boolean mRenderComplete; - - private final RectF mSourceRect = new RectF(); - private final RectF mTargetRect = new RectF(); - - private final LongSparseArray<Tile> mActiveTiles = new LongSparseArray<Tile>(); - - // The following three queue is guarded by TileImageView.this - private final TileQueue mRecycledQueue = new TileQueue(); - private final TileQueue mUploadQueue = new TileQueue(); - private final TileQueue mDecodeQueue = new TileQueue(); - - // The width and height of the full-sized bitmap - protected int mImageWidth = SIZE_UNKNOWN; - protected int mImageHeight = SIZE_UNKNOWN; - - protected int mCenterX; - protected int mCenterY; - protected float mScale; - protected int mRotation; - - // Temp variables to avoid memory allocation - private final Rect mTileRange = new Rect(); - private final Rect mActiveRange[] = {new Rect(), new Rect()}; - - private final TileUploader mTileUploader = new TileUploader(); - private boolean mIsTextureFreed; - private Future<Void> mTileDecoder; - private final ThreadPool mThreadPool; - private boolean mBackgroundTileUploaded; - - public static interface TileSource { - public int getLevelCount(); - public ScreenNail getScreenNail(); - public int getImageWidth(); - public int getImageHeight(); - - // The tile returned by this method can be specified this way: Assuming - // the image size is (width, height), first take the intersection of (0, - // 0) - (width, height) and (x, y) - (x + tileSize, y + tileSize). If - // in extending the region, we found some part of the region are outside - // the image, those pixels are filled with black. - // - // If level > 0, it does the same operation on a down-scaled version of - // the original image (down-scaled by a factor of 2^level), but (x, y) - // still refers to the coordinate on the original image. - // - // The method would be called in another thread. - public Bitmap getTile(int level, int x, int y, int tileSize); - } - - public static boolean isHighResolution(Context context) { - DisplayMetrics metrics = new DisplayMetrics(); - WindowManager wm = (WindowManager) - context.getSystemService(Context.WINDOW_SERVICE); - wm.getDefaultDisplay().getMetrics(metrics); - return metrics.heightPixels > 2048 || metrics.widthPixels > 2048; - } - - public TileImageView(GalleryContext context) { - mThreadPool = context.getThreadPool(); - mTileDecoder = mThreadPool.submit(new TileDecoder()); - if (sTileSize == 0) { - if (isHighResolution(context.getAndroidContext())) { - sTileSize = 512 ; - } else { - sTileSize = 256; - } - } - } - - public void setModel(TileSource model) { - mModel = model; - if (model != null) notifyModelInvalidated(); - } - - public void setScreenNail(ScreenNail s) { - mScreenNail = s; - } - - public void notifyModelInvalidated() { - invalidateTiles(); - if (mModel == null) { - mScreenNail = null; - mImageWidth = 0; - mImageHeight = 0; - mLevelCount = 0; - } else { - setScreenNail(mModel.getScreenNail()); - mImageWidth = mModel.getImageWidth(); - mImageHeight = mModel.getImageHeight(); - mLevelCount = mModel.getLevelCount(); - } - layoutTiles(mCenterX, mCenterY, mScale, mRotation); - invalidate(); - } - - @Override - protected void onLayout( - boolean changeSize, int left, int top, int right, int bottom) { - super.onLayout(changeSize, left, top, right, bottom); - if (changeSize) layoutTiles(mCenterX, mCenterY, mScale, mRotation); - } - - // Prepare the tiles we want to use for display. - // - // 1. Decide the tile level we want to use for display. - // 2. Decide the tile levels we want to keep as texture (in addition to - // the one we use for display). - // 3. Recycle unused tiles. - // 4. Activate the tiles we want. - private void layoutTiles(int centerX, int centerY, float scale, int rotation) { - // The width and height of this view. - int width = getWidth(); - int height = getHeight(); - - // The tile levels we want to keep as texture is in the range - // [fromLevel, endLevel). - int fromLevel; - int endLevel; - - // We want to use a texture larger than or equal to the display size. - mLevel = Utils.clamp(Utils.floorLog2(1f / scale), 0, mLevelCount); - - // We want to keep one more tile level as texture in addition to what - // we use for display. So it can be faster when the scale moves to the - // next level. We choose a level closer to the current scale. - if (mLevel != mLevelCount) { - Rect range = mTileRange; - getRange(range, centerX, centerY, mLevel, scale, rotation); - mOffsetX = Math.round(width / 2f + (range.left - centerX) * scale); - mOffsetY = Math.round(height / 2f + (range.top - centerY) * scale); - fromLevel = scale * (1 << mLevel) > 0.75f ? mLevel - 1 : mLevel; - } else { - // Activate the tiles of the smallest two levels. - fromLevel = mLevel - 2; - mOffsetX = Math.round(width / 2f - centerX * scale); - mOffsetY = Math.round(height / 2f - centerY * scale); - } - - fromLevel = Math.max(0, Math.min(fromLevel, mLevelCount - 2)); - endLevel = Math.min(fromLevel + 2, mLevelCount); - - Rect range[] = mActiveRange; - for (int i = fromLevel; i < endLevel; ++i) { - getRange(range[i - fromLevel], centerX, centerY, i, rotation); - } - - // If rotation is transient, don't update the tile. - if (rotation % 90 != 0) return; - - synchronized (this) { - mDecodeQueue.clean(); - mUploadQueue.clean(); - mBackgroundTileUploaded = false; - - // Recycle unused tiles: if the level of the active tile is outside the - // range [fromLevel, endLevel) or not in the visible range. - int n = mActiveTiles.size(); - for (int i = 0; i < n; i++) { - Tile tile = mActiveTiles.valueAt(i); - int level = tile.mTileLevel; - if (level < fromLevel || level >= endLevel - || !range[level - fromLevel].contains(tile.mX, tile.mY)) { - mActiveTiles.removeAt(i); - i--; - n--; - recycleTile(tile); - } - } - } - - for (int i = fromLevel; i < endLevel; ++i) { - int size = sTileSize << i; - Rect r = range[i - fromLevel]; - for (int y = r.top, bottom = r.bottom; y < bottom; y += size) { - for (int x = r.left, right = r.right; x < right; x += size) { - activateTile(x, y, i); - } - } - } - invalidate(); - } - - protected synchronized void invalidateTiles() { - mDecodeQueue.clean(); - mUploadQueue.clean(); - - // TODO disable decoder - int n = mActiveTiles.size(); - for (int i = 0; i < n; i++) { - Tile tile = mActiveTiles.valueAt(i); - recycleTile(tile); - } - mActiveTiles.clear(); - } - - private void getRange(Rect out, int cX, int cY, int level, int rotation) { - getRange(out, cX, cY, level, 1f / (1 << (level + 1)), rotation); - } - - // If the bitmap is scaled by the given factor "scale", return the - // rectangle containing visible range. The left-top coordinate returned is - // aligned to the tile boundary. - // - // (cX, cY) is the point on the original bitmap which will be put in the - // center of the ImageViewer. - private void getRange(Rect out, - int cX, int cY, int level, float scale, int rotation) { - - double radians = Math.toRadians(-rotation); - double w = getWidth(); - double h = getHeight(); - - double cos = Math.cos(radians); - double sin = Math.sin(radians); - int width = (int) Math.ceil(Math.max( - Math.abs(cos * w - sin * h), Math.abs(cos * w + sin * h))); - int height = (int) Math.ceil(Math.max( - Math.abs(sin * w + cos * h), Math.abs(sin * w - cos * h))); - - int left = (int) FloatMath.floor(cX - width / (2f * scale)); - int top = (int) FloatMath.floor(cY - height / (2f * scale)); - int right = (int) FloatMath.ceil(left + width / scale); - int bottom = (int) FloatMath.ceil(top + height / scale); - - // align the rectangle to tile boundary - int size = sTileSize << level; - left = Math.max(0, size * (left / size)); - top = Math.max(0, size * (top / size)); - right = Math.min(mImageWidth, right); - bottom = Math.min(mImageHeight, bottom); - - out.set(left, top, right, bottom); - } - - // Calculate where the center of the image is, in the view coordinates. - public void getImageCenter(Point center) { - // The width and height of this view. - int viewW = getWidth(); - int viewH = getHeight(); - - // The distance between the center of the view to the center of the - // bitmap, in bitmap units. (mCenterX and mCenterY are the bitmap - // coordinates correspond to the center of view) - int distW, distH; - if (mRotation % 180 == 0) { - distW = mImageWidth / 2 - mCenterX; - distH = mImageHeight / 2 - mCenterY; - } else { - distW = mImageHeight / 2 - mCenterY; - distH = mImageWidth / 2 - mCenterX; - } - - // Convert to view coordinates. mScale translates from bitmap units to - // view units. - center.x = Math.round(viewW / 2f + distW * mScale); - center.y = Math.round(viewH / 2f + distH * mScale); - } - - public boolean setPosition(int centerX, int centerY, float scale, int rotation) { - if (mCenterX == centerX && mCenterY == centerY - && mScale == scale && mRotation == rotation) return false; - mCenterX = centerX; - mCenterY = centerY; - mScale = scale; - mRotation = rotation; - layoutTiles(centerX, centerY, scale, rotation); - invalidate(); - return true; - } - - public void freeTextures() { - mIsTextureFreed = true; - - if (mTileDecoder != null) { - mTileDecoder.cancel(); - mTileDecoder.get(); - mTileDecoder = null; - } - - int n = mActiveTiles.size(); - for (int i = 0; i < n; i++) { - Tile texture = mActiveTiles.valueAt(i); - texture.recycle(); - } - mActiveTiles.clear(); - mTileRange.set(0, 0, 0, 0); - - synchronized (this) { - mUploadQueue.clean(); - mDecodeQueue.clean(); - Tile tile = mRecycledQueue.pop(); - while (tile != null) { - tile.recycle(); - tile = mRecycledQueue.pop(); - } - } - setScreenNail(null); - } - - public void prepareTextures() { - if (mTileDecoder == null) { - mTileDecoder = mThreadPool.submit(new TileDecoder()); - } - if (mIsTextureFreed) { - layoutTiles(mCenterX, mCenterY, mScale, mRotation); - mIsTextureFreed = false; - setScreenNail(mModel == null ? null : mModel.getScreenNail()); - } - } - - @Override - protected void render(GLCanvas canvas) { - mUploadQuota = UPLOAD_LIMIT; - mRenderComplete = true; - - int level = mLevel; - int rotation = mRotation; - int flags = 0; - if (rotation != 0) flags |= GLCanvas.SAVE_FLAG_MATRIX; - - if (flags != 0) { - canvas.save(flags); - if (rotation != 0) { - int centerX = getWidth() / 2, centerY = getHeight() / 2; - canvas.translate(centerX, centerY); - canvas.rotate(rotation, 0, 0, 1); - canvas.translate(-centerX, -centerY); - } - } - try { - if (level != mLevelCount && !isScreenNailAnimating()) { - if (mScreenNail != null) { - mScreenNail.noDraw(); - } - - int size = (sTileSize << level); - float length = size * mScale; - Rect r = mTileRange; - - for (int ty = r.top, i = 0; ty < r.bottom; ty += size, i++) { - float y = mOffsetY + i * length; - for (int tx = r.left, j = 0; tx < r.right; tx += size, j++) { - float x = mOffsetX + j * length; - drawTile(canvas, tx, ty, level, x, y, length); - } - } - } else if (mScreenNail != null) { - mScreenNail.draw(canvas, mOffsetX, mOffsetY, - Math.round(mImageWidth * mScale), - Math.round(mImageHeight * mScale)); - if (isScreenNailAnimating()) { - invalidate(); - } - } - } finally { - if (flags != 0) canvas.restore(); - } - - if (mRenderComplete) { - if (!mBackgroundTileUploaded) uploadBackgroundTiles(canvas); - } else { - invalidate(); - } - } - - private boolean isScreenNailAnimating() { - return (mScreenNail instanceof TiledScreenNail) - && ((TiledScreenNail) mScreenNail).isAnimating(); - } - - private void uploadBackgroundTiles(GLCanvas canvas) { - mBackgroundTileUploaded = true; - int n = mActiveTiles.size(); - for (int i = 0; i < n; i++) { - Tile tile = mActiveTiles.valueAt(i); - if (!tile.isContentValid()) queueForDecode(tile); - } - } - - void queueForUpload(Tile tile) { - synchronized (this) { - mUploadQueue.push(tile); - } - if (mTileUploader.mActive.compareAndSet(false, true)) { - getGLRoot().addOnGLIdleListener(mTileUploader); - } - } - - synchronized void queueForDecode(Tile tile) { - if (tile.mTileState == STATE_ACTIVATED) { - tile.mTileState = STATE_IN_QUEUE; - if (mDecodeQueue.push(tile)) notifyAll(); - } - } - - boolean decodeTile(Tile tile) { - synchronized (this) { - if (tile.mTileState != STATE_IN_QUEUE) return false; - tile.mTileState = STATE_DECODING; - } - boolean decodeComplete = tile.decode(); - synchronized (this) { - if (tile.mTileState == STATE_RECYCLING) { - tile.mTileState = STATE_RECYCLED; - if (tile.mDecodedTile != null) { - GalleryBitmapPool.getInstance().put(tile.mDecodedTile); - tile.mDecodedTile = null; - } - mRecycledQueue.push(tile); - return false; - } - tile.mTileState = decodeComplete ? STATE_DECODED : STATE_DECODE_FAIL; - return decodeComplete; - } - } - - private synchronized Tile obtainTile(int x, int y, int level) { - Tile tile = mRecycledQueue.pop(); - if (tile != null) { - tile.mTileState = STATE_ACTIVATED; - tile.update(x, y, level); - return tile; - } - return new Tile(x, y, level); - } - - synchronized void recycleTile(Tile tile) { - if (tile.mTileState == STATE_DECODING) { - tile.mTileState = STATE_RECYCLING; - return; - } - tile.mTileState = STATE_RECYCLED; - if (tile.mDecodedTile != null) { - GalleryBitmapPool.getInstance().put(tile.mDecodedTile); - tile.mDecodedTile = null; - } - mRecycledQueue.push(tile); - } - - private void activateTile(int x, int y, int level) { - long key = makeTileKey(x, y, level); - Tile tile = mActiveTiles.get(key); - if (tile != null) { - if (tile.mTileState == STATE_IN_QUEUE) { - tile.mTileState = STATE_ACTIVATED; - } - return; - } - tile = obtainTile(x, y, level); - mActiveTiles.put(key, tile); - } - - private Tile getTile(int x, int y, int level) { - return mActiveTiles.get(makeTileKey(x, y, level)); - } - - private static long makeTileKey(int x, int y, int level) { - long result = x; - result = (result << 16) | y; - result = (result << 16) | level; - return result; - } - - private class TileUploader implements GLRoot.OnGLIdleListener { - AtomicBoolean mActive = new AtomicBoolean(false); - - @Override - public boolean onGLIdle(GLCanvas canvas, boolean renderRequested) { - // Skips uploading if there is a pending rendering request. - // Returns true to keep uploading in next rendering loop. - if (renderRequested) return true; - int quota = UPLOAD_LIMIT; - Tile tile = null; - while (quota > 0) { - synchronized (TileImageView.this) { - tile = mUploadQueue.pop(); - } - if (tile == null) break; - if (!tile.isContentValid()) { - boolean hasBeenLoaded = tile.isLoaded(); - Utils.assertTrue(tile.mTileState == STATE_DECODED); - tile.updateContent(canvas); - if (!hasBeenLoaded) tile.draw(canvas, 0, 0); - --quota; - } - } - if (tile == null) mActive.set(false); - return tile != null; - } - } - - // Draw the tile to a square at canvas that locates at (x, y) and - // has a side length of length. - public void drawTile(GLCanvas canvas, - int tx, int ty, int level, float x, float y, float length) { - RectF source = mSourceRect; - RectF target = mTargetRect; - target.set(x, y, x + length, y + length); - source.set(0, 0, sTileSize, sTileSize); - - Tile tile = getTile(tx, ty, level); - if (tile != null) { - if (!tile.isContentValid()) { - if (tile.mTileState == STATE_DECODED) { - if (mUploadQuota > 0) { - --mUploadQuota; - tile.updateContent(canvas); - } else { - mRenderComplete = false; - } - } else if (tile.mTileState != STATE_DECODE_FAIL){ - mRenderComplete = false; - queueForDecode(tile); - } - } - if (drawTile(tile, canvas, source, target)) return; - } - if (mScreenNail != null) { - int size = sTileSize << level; - float scaleX = (float) mScreenNail.getWidth() / mImageWidth; - float scaleY = (float) mScreenNail.getHeight() / mImageHeight; - source.set(tx * scaleX, ty * scaleY, (tx + size) * scaleX, - (ty + size) * scaleY); - mScreenNail.draw(canvas, source, target); - } - } - - static boolean drawTile( - Tile tile, GLCanvas canvas, RectF source, RectF target) { - while (true) { - if (tile.isContentValid()) { - canvas.drawTexture(tile, source, target); - return true; - } - - // Parent can be divided to four quads and tile is one of the four. - Tile parent = tile.getParentTile(); - if (parent == null) return false; - if (tile.mX == parent.mX) { - source.left /= 2f; - source.right /= 2f; - } else { - source.left = (sTileSize + source.left) / 2f; - source.right = (sTileSize + source.right) / 2f; - } - if (tile.mY == parent.mY) { - source.top /= 2f; - source.bottom /= 2f; - } else { - source.top = (sTileSize + source.top) / 2f; - source.bottom = (sTileSize + source.bottom) / 2f; - } - tile = parent; - } - } - - private class Tile extends UploadedTexture { - public int mX; - public int mY; - public int mTileLevel; - public Tile mNext; - public Bitmap mDecodedTile; - public volatile int mTileState = STATE_ACTIVATED; - - public Tile(int x, int y, int level) { - mX = x; - mY = y; - mTileLevel = level; - } - - @Override - protected void onFreeBitmap(Bitmap bitmap) { - GalleryBitmapPool.getInstance().put(bitmap); - } - - boolean decode() { - // Get a tile from the original image. The tile is down-scaled - // by (1 << mTilelevel) from a region in the original image. - try { - mDecodedTile = DecodeUtils.ensureGLCompatibleBitmap(mModel.getTile( - mTileLevel, mX, mY, sTileSize)); - } catch (Throwable t) { - Log.w(TAG, "fail to decode tile", t); - } - return mDecodedTile != null; - } - - @Override - protected Bitmap onGetBitmap() { - Utils.assertTrue(mTileState == STATE_DECODED); - - // We need to override the width and height, so that we won't - // draw beyond the boundaries. - int rightEdge = ((mImageWidth - mX) >> mTileLevel); - int bottomEdge = ((mImageHeight - mY) >> mTileLevel); - setSize(Math.min(sTileSize, rightEdge), Math.min(sTileSize, bottomEdge)); - - Bitmap bitmap = mDecodedTile; - mDecodedTile = null; - mTileState = STATE_ACTIVATED; - return bitmap; - } - - // We override getTextureWidth() and getTextureHeight() here, so the - // texture can be re-used for different tiles regardless of the actual - // size of the tile (which may be small because it is a tile at the - // boundary). - @Override - public int getTextureWidth() { - return sTileSize; - } - - @Override - public int getTextureHeight() { - return sTileSize; - } - - public void update(int x, int y, int level) { - mX = x; - mY = y; - mTileLevel = level; - invalidateContent(); - } - - public Tile getParentTile() { - if (mTileLevel + 1 == mLevelCount) return null; - int size = sTileSize << (mTileLevel + 1); - int x = size * (mX / size); - int y = size * (mY / size); - return getTile(x, y, mTileLevel + 1); - } - - @Override - public String toString() { - return String.format("tile(%s, %s, %s / %s)", - mX / sTileSize, mY / sTileSize, mLevel, mLevelCount); - } - } - - private static class TileQueue { - private Tile mHead; - - public Tile pop() { - Tile tile = mHead; - if (tile != null) mHead = tile.mNext; - return tile; - } - - public boolean push(Tile tile) { - boolean wasEmpty = mHead == null; - tile.mNext = mHead; - mHead = tile; - return wasEmpty; - } - - public void clean() { - mHead = null; - } - } - - private class TileDecoder implements ThreadPool.Job<Void> { - - private CancelListener mNotifier = new CancelListener() { - @Override - public void onCancel() { - synchronized (TileImageView.this) { - TileImageView.this.notifyAll(); - } - } - }; - - @Override - public Void run(JobContext jc) { - jc.setMode(ThreadPool.MODE_NONE); - jc.setCancelListener(mNotifier); - while (!jc.isCancelled()) { - Tile tile = null; - synchronized(TileImageView.this) { - tile = mDecodeQueue.pop(); - if (tile == null && !jc.isCancelled()) { - Utils.waitWithoutInterrupt(TileImageView.this); - } - } - if (tile == null) continue; - if (decodeTile(tile)) queueForUpload(tile); - } - return null; - } - } -} diff --git a/src/com/android/gallery3d/ui/TileImageViewAdapter.java b/src/com/android/gallery3d/ui/TileImageViewAdapter.java deleted file mode 100644 index 0c1f66d0c..000000000 --- a/src/com/android/gallery3d/ui/TileImageViewAdapter.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * 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.ui; - -import android.annotation.TargetApi; -import android.graphics.Bitmap; -import android.graphics.Bitmap.Config; -import android.graphics.BitmapFactory; -import android.graphics.BitmapRegionDecoder; -import android.graphics.Canvas; -import android.graphics.Rect; - -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.common.Utils; -import com.android.photos.data.GalleryBitmapPool; - -public class TileImageViewAdapter implements TileImageView.TileSource { - private static final String TAG = "TileImageViewAdapter"; - protected ScreenNail mScreenNail; - protected boolean mOwnScreenNail; - protected BitmapRegionDecoder mRegionDecoder; - protected int mImageWidth; - protected int mImageHeight; - protected int mLevelCount; - - public TileImageViewAdapter() { - } - - public synchronized void clear() { - mScreenNail = null; - mImageWidth = 0; - mImageHeight = 0; - mLevelCount = 0; - mRegionDecoder = null; - } - - // Caller is responsible to recycle the ScreenNail - public synchronized void setScreenNail( - ScreenNail screenNail, int width, int height) { - Utils.checkNotNull(screenNail); - mScreenNail = screenNail; - mImageWidth = width; - mImageHeight = height; - mRegionDecoder = null; - mLevelCount = 0; - } - - public synchronized void setRegionDecoder(BitmapRegionDecoder decoder) { - mRegionDecoder = Utils.checkNotNull(decoder); - mImageWidth = decoder.getWidth(); - mImageHeight = decoder.getHeight(); - mLevelCount = calculateLevelCount(); - } - - private int calculateLevelCount() { - return Math.max(0, Utils.ceilLog2( - (float) mImageWidth / mScreenNail.getWidth())); - } - - // Gets a sub image on a rectangle of the current photo. For example, - // getTile(1, 50, 50, 100, 3, pool) means to get the region located - // at (50, 50) with sample level 1 (ie, down sampled by 2^1) and the - // target tile size (after sampling) 100 with border 3. - // - // From this spec, we can infer the actual tile size to be - // 100 + 3x2 = 106, and the size of the region to be extracted from the - // photo to be 200 with border 6. - // - // As a result, we should decode region (50-6, 50-6, 250+6, 250+6) or - // (44, 44, 256, 256) from the original photo and down sample it to 106. - @TargetApi(ApiHelper.VERSION_CODES.HONEYCOMB) - @Override - public Bitmap getTile(int level, int x, int y, int tileSize) { - if (!ApiHelper.HAS_REUSING_BITMAP_IN_BITMAP_REGION_DECODER) { - return getTileWithoutReusingBitmap(level, x, y, tileSize); - } - - int t = tileSize << level; - - Rect wantRegion = new Rect(x, y, x + t, y + t); - - boolean needClear; - BitmapRegionDecoder regionDecoder = null; - - synchronized (this) { - regionDecoder = mRegionDecoder; - if (regionDecoder == null) return null; - - // We need to clear a reused bitmap, if wantRegion is not fully - // within the image. - needClear = !new Rect(0, 0, mImageWidth, mImageHeight) - .contains(wantRegion); - } - - Bitmap bitmap = GalleryBitmapPool.getInstance().get(tileSize, tileSize); - if (bitmap != null) { - if (needClear) bitmap.eraseColor(0); - } else { - bitmap = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888); - } - - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Config.ARGB_8888; - options.inPreferQualityOverSpeed = true; - options.inSampleSize = (1 << level); - options.inBitmap = bitmap; - - try { - // In CropImage, we may call the decodeRegion() concurrently. - synchronized (regionDecoder) { - bitmap = regionDecoder.decodeRegion(wantRegion, options); - } - } finally { - if (options.inBitmap != bitmap && options.inBitmap != null) { - GalleryBitmapPool.getInstance().put(options.inBitmap); - options.inBitmap = null; - } - } - - if (bitmap == null) { - Log.w(TAG, "fail in decoding region"); - } - return bitmap; - } - - private Bitmap getTileWithoutReusingBitmap( - int level, int x, int y, int tileSize) { - int t = tileSize << level; - Rect wantRegion = new Rect(x, y, x + t, y + t); - - BitmapRegionDecoder regionDecoder; - Rect overlapRegion; - - synchronized (this) { - regionDecoder = mRegionDecoder; - if (regionDecoder == null) return null; - overlapRegion = new Rect(0, 0, mImageWidth, mImageHeight); - Utils.assertTrue(overlapRegion.intersect(wantRegion)); - } - - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Config.ARGB_8888; - options.inPreferQualityOverSpeed = true; - options.inSampleSize = (1 << level); - Bitmap bitmap = null; - - // In CropImage, we may call the decodeRegion() concurrently. - synchronized (regionDecoder) { - bitmap = regionDecoder.decodeRegion(overlapRegion, options); - } - - if (bitmap == null) { - Log.w(TAG, "fail in decoding region"); - } - - if (wantRegion.equals(overlapRegion)) return bitmap; - - Bitmap result = Bitmap.createBitmap(tileSize, tileSize, Config.ARGB_8888); - Canvas canvas = new Canvas(result); - canvas.drawBitmap(bitmap, - (overlapRegion.left - wantRegion.left) >> level, - (overlapRegion.top - wantRegion.top) >> level, null); - return result; - } - - - @Override - public ScreenNail getScreenNail() { - return mScreenNail; - } - - @Override - public int getImageHeight() { - return mImageHeight; - } - - @Override - public int getImageWidth() { - return mImageWidth; - } - - @Override - public int getLevelCount() { - return mLevelCount; - } -} diff --git a/src/com/android/gallery3d/ui/TiledScreenNail.java b/src/com/android/gallery3d/ui/TiledScreenNail.java deleted file mode 100644 index 860e230bb..000000000 --- a/src/com/android/gallery3d/ui/TiledScreenNail.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.graphics.Bitmap; -import android.graphics.RectF; - -import com.android.gallery3d.common.Utils; -import com.android.photos.data.GalleryBitmapPool; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.TiledTexture; - -// This is a ScreenNail wraps a Bitmap. There are some extra functions: -// -// - If we need to draw before the bitmap is available, we draw a rectange of -// placeholder color (gray). -// -// - When the the bitmap is available, and we have drawn the placeholder color -// before, we will do a fade-in animation. -public class TiledScreenNail implements ScreenNail { - @SuppressWarnings("unused") - private static final String TAG = "TiledScreenNail"; - - // The duration of the fading animation in milliseconds - private static final int DURATION = 180; - - private static int sMaxSide = 640; - - // These are special values for mAnimationStartTime - private static final long ANIMATION_NOT_NEEDED = -1; - private static final long ANIMATION_NEEDED = -2; - private static final long ANIMATION_DONE = -3; - - private int mWidth; - private int mHeight; - private long mAnimationStartTime = ANIMATION_NOT_NEEDED; - - private Bitmap mBitmap; - private TiledTexture mTexture; - - public TiledScreenNail(Bitmap bitmap) { - mWidth = bitmap.getWidth(); - mHeight = bitmap.getHeight(); - mBitmap = bitmap; - mTexture = new TiledTexture(bitmap); - } - - public TiledScreenNail(int width, int height) { - setSize(width, height); - } - - // This gets overridden by bitmap_screennail_placeholder - // in GalleryUtils.initialize - private static int mPlaceholderColor = 0xFF222222; - private static boolean mDrawPlaceholder = true; - - public static void setPlaceholderColor(int color) { - mPlaceholderColor = color; - } - - private void setSize(int width, int height) { - if (width == 0 || height == 0) { - width = sMaxSide; - height = sMaxSide * 3 / 4; - } - float scale = Math.min(1, (float) sMaxSide / Math.max(width, height)); - mWidth = Math.round(scale * width); - mHeight = Math.round(scale * height); - } - - // Combines the two ScreenNails. - // Returns the used one and recycle the unused one. - public ScreenNail combine(ScreenNail other) { - if (other == null) { - return this; - } - - if (!(other instanceof TiledScreenNail)) { - recycle(); - return other; - } - - // Now both are TiledScreenNail. Move over the information about width, - // height, and Bitmap, then recycle the other. - TiledScreenNail newer = (TiledScreenNail) other; - mWidth = newer.mWidth; - mHeight = newer.mHeight; - if (newer.mTexture != null) { - if (mBitmap != null) GalleryBitmapPool.getInstance().put(mBitmap); - if (mTexture != null) mTexture.recycle(); - mBitmap = newer.mBitmap; - mTexture = newer.mTexture; - newer.mBitmap = null; - newer.mTexture = null; - } - newer.recycle(); - return this; - } - - public void updatePlaceholderSize(int width, int height) { - if (mBitmap != null) return; - if (width == 0 || height == 0) return; - setSize(width, height); - } - - @Override - public int getWidth() { - return mWidth; - } - - @Override - public int getHeight() { - return mHeight; - } - - @Override - public void noDraw() { - } - - @Override - public void recycle() { - if (mTexture != null) { - mTexture.recycle(); - mTexture = null; - } - if (mBitmap != null) { - GalleryBitmapPool.getInstance().put(mBitmap); - mBitmap = null; - } - } - - public static void disableDrawPlaceholder() { - mDrawPlaceholder = false; - } - - public static void enableDrawPlaceholder() { - mDrawPlaceholder = true; - } - - @Override - public void draw(GLCanvas canvas, int x, int y, int width, int height) { - if (mTexture == null || !mTexture.isReady()) { - if (mAnimationStartTime == ANIMATION_NOT_NEEDED) { - mAnimationStartTime = ANIMATION_NEEDED; - } - if(mDrawPlaceholder) { - canvas.fillRect(x, y, width, height, mPlaceholderColor); - } - return; - } - - if (mAnimationStartTime == ANIMATION_NEEDED) { - mAnimationStartTime = AnimationTime.get(); - } - - if (isAnimating()) { - mTexture.drawMixed(canvas, mPlaceholderColor, getRatio(), x, y, - width, height); - } else { - mTexture.draw(canvas, x, y, width, height); - } - } - - @Override - public void draw(GLCanvas canvas, RectF source, RectF dest) { - if (mTexture == null || !mTexture.isReady()) { - canvas.fillRect(dest.left, dest.top, dest.width(), dest.height(), - mPlaceholderColor); - return; - } - - mTexture.draw(canvas, source, dest); - } - - public boolean isAnimating() { - // The TiledTexture may not be uploaded completely yet. - // In that case, we count it as animating state and we will draw - // the placeholder in TileImageView. - if (mTexture == null || !mTexture.isReady()) return true; - if (mAnimationStartTime < 0) return false; - if (AnimationTime.get() - mAnimationStartTime >= DURATION) { - mAnimationStartTime = ANIMATION_DONE; - return false; - } - return true; - } - - private float getRatio() { - float r = (float) (AnimationTime.get() - mAnimationStartTime) / DURATION; - return Utils.clamp(1.0f - r, 0.0f, 1.0f); - } - - public boolean isShowingPlaceholder() { - return (mBitmap == null) || isAnimating(); - } - - public TiledTexture getTexture() { - return mTexture; - } - - public static void setMaxSide(int size) { - sMaxSide = size; - } -} diff --git a/src/com/android/gallery3d/ui/UndoBarView.java b/src/com/android/gallery3d/ui/UndoBarView.java deleted file mode 100644 index 42f12ae72..000000000 --- a/src/com/android/gallery3d/ui/UndoBarView.java +++ /dev/null @@ -1,211 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.content.Context; -import android.view.MotionEvent; - -import com.android.gallery3d.R; -import com.android.gallery3d.common.Utils; -import com.android.gallery3d.glrenderer.GLCanvas; -import com.android.gallery3d.glrenderer.NinePatchTexture; -import com.android.gallery3d.glrenderer.ResourceTexture; -import com.android.gallery3d.glrenderer.StringTexture; -import com.android.gallery3d.util.GalleryUtils; - -public class UndoBarView extends GLView { - @SuppressWarnings("unused") - private static final String TAG = "UndoBarView"; - - private static final int WHITE = 0xFFFFFFFF; - private static final int GRAY = 0xFFAAAAAA; - - private final NinePatchTexture mPanel; - private final StringTexture mUndoText; - private final StringTexture mDeletedText; - private final ResourceTexture mUndoIcon; - private final int mBarHeight; - private final int mBarMargin; - private final int mUndoTextMargin; - private final int mIconSize; - private final int mIconMargin; - private final int mSeparatorTopMargin; - private final int mSeparatorBottomMargin; - private final int mSeparatorRightMargin; - private final int mSeparatorWidth; - private final int mDeletedTextMargin; - private final int mClickRegion; - - private OnClickListener mOnClickListener; - private boolean mDownOnButton; - - // This is the layout of UndoBarView. The unit is dp. - // - // +-+----+----------------+-+--+----+-+------+--+-+ - // 48 | | | Deleted | | | <- | | UNDO | | | - // +-+----+----------------+-+--+----+-+------+--+-+ - // 4 16 1 12 32 8 16 4 - public UndoBarView(Context context) { - mBarHeight = GalleryUtils.dpToPixel(48); - mBarMargin = GalleryUtils.dpToPixel(4); - mUndoTextMargin = GalleryUtils.dpToPixel(16); - mIconMargin = GalleryUtils.dpToPixel(8); - mIconSize = GalleryUtils.dpToPixel(32); - mSeparatorRightMargin = GalleryUtils.dpToPixel(12); - mSeparatorTopMargin = GalleryUtils.dpToPixel(10); - mSeparatorBottomMargin = GalleryUtils.dpToPixel(10); - mSeparatorWidth = GalleryUtils.dpToPixel(1); - mDeletedTextMargin = GalleryUtils.dpToPixel(16); - - mPanel = new NinePatchTexture(context, R.drawable.panel_undo_holo); - mUndoText = StringTexture.newInstance(context.getString(R.string.undo), - GalleryUtils.dpToPixel(12), GRAY, 0, true); - mDeletedText = StringTexture.newInstance( - context.getString(R.string.deleted), - GalleryUtils.dpToPixel(16), WHITE); - mUndoIcon = new ResourceTexture( - context, R.drawable.ic_menu_revert_holo_dark); - mClickRegion = mBarMargin + mUndoTextMargin + mUndoText.getWidth() - + mIconMargin + mIconSize + mSeparatorRightMargin; - } - - public void setOnClickListener(OnClickListener listener) { - mOnClickListener = listener; - } - - @Override - protected void onMeasure(int widthSpec, int heightSpec) { - setMeasuredSize(0 /* unused */, mBarHeight); - } - - @Override - protected void render(GLCanvas canvas) { - super.render(canvas); - advanceAnimation(); - - canvas.save(GLCanvas.SAVE_FLAG_ALPHA); - canvas.multiplyAlpha(mAlpha); - - int w = getWidth(); - int h = getHeight(); - mPanel.draw(canvas, mBarMargin, 0, w - mBarMargin * 2, mBarHeight); - - int x = w - mBarMargin; - int y; - - x -= mUndoTextMargin + mUndoText.getWidth(); - y = (mBarHeight - mUndoText.getHeight()) / 2; - mUndoText.draw(canvas, x, y); - - x -= mIconMargin + mIconSize; - y = (mBarHeight - mIconSize) / 2; - mUndoIcon.draw(canvas, x, y, mIconSize, mIconSize); - - x -= mSeparatorRightMargin + mSeparatorWidth; - y = mSeparatorTopMargin; - canvas.fillRect(x, y, mSeparatorWidth, - mBarHeight - mSeparatorTopMargin - mSeparatorBottomMargin, GRAY); - - x = mBarMargin + mDeletedTextMargin; - y = (mBarHeight - mDeletedText.getHeight()) / 2; - mDeletedText.draw(canvas, x, y); - - canvas.restore(); - } - - @Override - protected boolean onTouch(MotionEvent event) { - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - mDownOnButton = inUndoButton(event); - break; - case MotionEvent.ACTION_UP: - if (mDownOnButton) { - if (mOnClickListener != null && inUndoButton(event)) { - mOnClickListener.onClick(this); - } - mDownOnButton = false; - } - break; - case MotionEvent.ACTION_CANCEL: - mDownOnButton = false; - break; - } - return true; - } - - // Check if the event is on the right of the separator - private boolean inUndoButton(MotionEvent event) { - float x = event.getX(); - float y = event.getY(); - int w = getWidth(); - int h = getHeight(); - return (x >= w - mClickRegion && x < w && y >= 0 && y < h); - } - - //////////////////////////////////////////////////////////////////////////// - // Alpha Animation - //////////////////////////////////////////////////////////////////////////// - - private static final long NO_ANIMATION = -1; - private static long ANIM_TIME = 200; - private long mAnimationStartTime = NO_ANIMATION; - private float mFromAlpha, mToAlpha; - private float mAlpha; - - private static float getTargetAlpha(int visibility) { - return (visibility == VISIBLE) ? 1f : 0f; - } - - @Override - public void setVisibility(int visibility) { - mAlpha = getTargetAlpha(visibility); - mAnimationStartTime = NO_ANIMATION; - super.setVisibility(visibility); - invalidate(); - } - - public void animateVisibility(int visibility) { - float target = getTargetAlpha(visibility); - if (mAnimationStartTime == NO_ANIMATION && mAlpha == target) return; - if (mAnimationStartTime != NO_ANIMATION && mToAlpha == target) return; - - mFromAlpha = mAlpha; - mToAlpha = target; - mAnimationStartTime = AnimationTime.startTime(); - - super.setVisibility(VISIBLE); - invalidate(); - } - - private void advanceAnimation() { - if (mAnimationStartTime == NO_ANIMATION) return; - - float delta = (float) (AnimationTime.get() - mAnimationStartTime) / - ANIM_TIME; - mAlpha = mFromAlpha + ((mToAlpha > mFromAlpha) ? delta : -delta); - mAlpha = Utils.clamp(mAlpha, 0f, 1f); - - if (mAlpha == mToAlpha) { - mAnimationStartTime = NO_ANIMATION; - if (mAlpha == 0) { - super.setVisibility(INVISIBLE); - } - } - invalidate(); - } -} diff --git a/src/com/android/gallery3d/ui/UserInteractionListener.java b/src/com/android/gallery3d/ui/UserInteractionListener.java deleted file mode 100644 index bc4a71800..000000000 --- a/src/com/android/gallery3d/ui/UserInteractionListener.java +++ /dev/null @@ -1,26 +0,0 @@ -/* - * 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.ui; - -public interface UserInteractionListener { - // Called when a user interaction begins (for example, fling). - public void onUserInteractionBegin(); - // Called when the user interaction ends. - public void onUserInteractionEnd(); - // Other one-shot user interactions. - public void onUserInteraction(); -} diff --git a/src/com/android/gallery3d/ui/WakeLockHoldingProgressListener.java b/src/com/android/gallery3d/ui/WakeLockHoldingProgressListener.java deleted file mode 100644 index ee61d8edb..000000000 --- a/src/com/android/gallery3d/ui/WakeLockHoldingProgressListener.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (C) 2012 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.ui; - -import android.app.Activity; -import android.content.Context; -import android.os.PowerManager; - -import com.android.gallery3d.app.AbstractGalleryActivity; - -public class WakeLockHoldingProgressListener implements MenuExecutor.ProgressListener { - static private final String DEFAULT_WAKE_LOCK_LABEL = "Gallery Progress Listener"; - private AbstractGalleryActivity mActivity; - private PowerManager.WakeLock mWakeLock; - - public WakeLockHoldingProgressListener(AbstractGalleryActivity galleryActivity) { - this(galleryActivity, DEFAULT_WAKE_LOCK_LABEL); - } - - public WakeLockHoldingProgressListener(AbstractGalleryActivity galleryActivity, String label) { - mActivity = galleryActivity; - PowerManager pm = - (PowerManager) ((Activity) mActivity).getSystemService(Context.POWER_SERVICE); - mWakeLock = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, label); - } - - @Override - public void onProgressComplete(int result) { - mWakeLock.release(); - } - - @Override - public void onProgressStart() { - mWakeLock.acquire(); - } - - protected AbstractGalleryActivity getActivity() { - return mActivity; - } - - @Override - public void onProgressUpdate(int index) { - } - - @Override - public void onConfirmDialogDismissed(boolean confirmed) { - } - - @Override - public void onConfirmDialogShown() { - } -} |