summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/ui')
-rw-r--r--src/com/android/gallery3d/ui/AbstractSlotRenderer.java119
-rw-r--r--src/com/android/gallery3d/ui/ActionModeHandler.java501
-rw-r--r--src/com/android/gallery3d/ui/AlbumLabelMaker.java206
-rw-r--r--src/com/android/gallery3d/ui/AlbumSetSlidingWindow.java549
-rw-r--r--src/com/android/gallery3d/ui/AlbumSetSlotRenderer.java242
-rw-r--r--src/com/android/gallery3d/ui/AlbumSlidingWindow.java365
-rw-r--r--src/com/android/gallery3d/ui/AlbumSlotRenderer.java201
-rw-r--r--src/com/android/gallery3d/ui/AnimationTime.java45
-rw-r--r--src/com/android/gallery3d/ui/BitmapLoader.java108
-rw-r--r--src/com/android/gallery3d/ui/BitmapScreenNail.java61
-rw-r--r--src/com/android/gallery3d/ui/BitmapTileProvider.java103
-rw-r--r--src/com/android/gallery3d/ui/CacheStorageUsageInfo.java90
-rw-r--r--src/com/android/gallery3d/ui/CaptureAnimation.java56
-rw-r--r--src/com/android/gallery3d/ui/DetailsAddressResolver.java118
-rw-r--r--src/com/android/gallery3d/ui/DetailsHelper.java148
-rw-r--r--src/com/android/gallery3d/ui/DialogDetailsView.java288
-rw-r--r--src/com/android/gallery3d/ui/DownUpDetector.java61
-rw-r--r--src/com/android/gallery3d/ui/EdgeEffect.java443
-rw-r--r--src/com/android/gallery3d/ui/EdgeView.java132
-rw-r--r--src/com/android/gallery3d/ui/FlingScroller.java141
-rw-r--r--src/com/android/gallery3d/ui/GLRoot.java53
-rw-r--r--src/com/android/gallery3d/ui/GLRootView.java630
-rw-r--r--src/com/android/gallery3d/ui/GLView.java465
-rw-r--r--src/com/android/gallery3d/ui/GestureRecognizer.java132
-rw-r--r--src/com/android/gallery3d/ui/Log.java54
-rw-r--r--src/com/android/gallery3d/ui/ManageCacheDrawer.java116
-rw-r--r--src/com/android/gallery3d/ui/MeasureHelper.java65
-rw-r--r--src/com/android/gallery3d/ui/MenuExecutor.java448
-rw-r--r--src/com/android/gallery3d/ui/OrientationSource.java22
-rw-r--r--src/com/android/gallery3d/ui/Paper.java183
-rw-r--r--src/com/android/gallery3d/ui/PhotoFallbackEffect.java179
-rw-r--r--src/com/android/gallery3d/ui/PhotoView.java1858
-rw-r--r--src/com/android/gallery3d/ui/PopupList.java206
-rw-r--r--src/com/android/gallery3d/ui/PositionController.java1821
-rw-r--r--src/com/android/gallery3d/ui/PreparePageFadeoutTexture.java85
-rw-r--r--src/com/android/gallery3d/ui/ProgressSpinner.java80
-rw-r--r--src/com/android/gallery3d/ui/RelativePosition.java42
-rw-r--r--src/com/android/gallery3d/ui/ScreenNail.java35
-rw-r--r--src/com/android/gallery3d/ui/ScrollBarView.java97
-rw-r--r--src/com/android/gallery3d/ui/ScrollerHelper.java97
-rw-r--r--src/com/android/gallery3d/ui/SelectionManager.java251
-rw-r--r--src/com/android/gallery3d/ui/SelectionMenu.java61
-rw-r--r--src/com/android/gallery3d/ui/SlideshowView.java163
-rw-r--r--src/com/android/gallery3d/ui/SlotView.java788
-rw-r--r--src/com/android/gallery3d/ui/SurfaceTextureScreenNail.java142
-rw-r--r--src/com/android/gallery3d/ui/SynchronizedHandler.java41
-rw-r--r--src/com/android/gallery3d/ui/TileImageView.java786
-rw-r--r--src/com/android/gallery3d/ui/TileImageViewAdapter.java200
-rw-r--r--src/com/android/gallery3d/ui/TiledScreenNail.java218
-rw-r--r--src/com/android/gallery3d/ui/UndoBarView.java211
-rw-r--r--src/com/android/gallery3d/ui/UserInteractionListener.java26
-rw-r--r--src/com/android/gallery3d/ui/WakeLockHoldingProgressListener.java66
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() {
- }
-}