diff options
| author | Ravi Banuri <ravibanuri@codeaurora.org> | 2015-10-20 19:41:58 +0530 |
|---|---|---|
| committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2015-11-08 22:55:59 -0800 |
| commit | c963ee889ea7e1f05c51129a8c742f8cfd874047 (patch) | |
| tree | edadc802543d7898189713a1ca06a96228a27024 | |
| parent | 7a41c376e299d9944a956004c5176b31a5ef0a4e (diff) | |
| download | android_packages_apps_Gallery2-c963ee889ea7e1f05c51129a8c742f8cfd874047.tar.gz android_packages_apps_Gallery2-c963ee889ea7e1f05c51129a8c742f8cfd874047.tar.bz2 android_packages_apps_Gallery2-c963ee889ea7e1f05c51129a8c742f8cfd874047.zip | |
Gallery: Gallery UX enhancement
Modified aosp files to change Gallery2 application UI
according to UX specification document.
Change-Id: I8f2668a6339371460cb772097a9a5987d02e5b5a
CRs-Fixed: 926603
| -rw-r--r-- | res/layout/filtershow_actionbar_effects.xml | 140 | ||||
| -rwxr-xr-x[-rw-r--r--] | src/com/android/gallery3d/app/TimeLineDataLoader.java | 72 | ||||
| -rwxr-xr-x[-rw-r--r--] | src/com/android/gallery3d/app/TimeLinePage.java | 414 | ||||
| -rwxr-xr-x[-rw-r--r--] | src/com/android/gallery3d/data/TimeLineTitleMediaItem.java | 360 | ||||
| -rw-r--r-- | src/com/android/gallery3d/ui/TimeLineSlidingWindow.java | 143 | ||||
| -rw-r--r-- | src/com/android/gallery3d/ui/TimeLineSlotRenderer.java | 160 | ||||
| -rw-r--r-- | src/com/android/gallery3d/ui/TimeLineSlotView.java | 760 | ||||
| -rwxr-xr-x[-rw-r--r--] | src/com/android/gallery3d/ui/TimeLineTitleMaker.java | 229 |
8 files changed, 958 insertions, 1320 deletions
diff --git a/res/layout/filtershow_actionbar_effects.xml b/res/layout/filtershow_actionbar_effects.xml index 995399618..90554bbf2 100644 --- a/res/layout/filtershow_actionbar_effects.xml +++ b/res/layout/filtershow_actionbar_effects.xml @@ -2,6 +2,7 @@ <!-- Copyright (C) 2013 The Android Open Source Project + Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at @@ -16,107 +17,54 @@ --> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/top" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical" + android:layout_height="48dip" + android:baselineAligned="false" + android:orientation="horizontal" android:visibility="visible" > - <View - android:background="@color/toolbar_separation_line" - android:layout_height="1dip" - android:layout_width="match_parent"/> + <ImageButton + android:id="@+id/cancelFilter" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:layout_gravity="left|center_vertical" + android:layout_weight=".1" + android:background="@android:color/transparent" + android:gravity="center" + android:src="@drawable/ic_menu_cancel_holo_light" + android:textSize="18dip" /> <LinearLayout + android:id="@+id/panelAccessoryViewList" android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="vertical"> - - <LinearLayout - android:id="@+id/controlArea" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:orientation="horizontal" - android:layout_alignParentBottom="true" - android:visibility="visible"> - - <SeekBar - android:id="@+id/primarySeekBar" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:layout_gravity="center_vertical" - style="@style/FilterShowSlider"/> - - </LinearLayout> - - <LinearLayout - android:layout_width="match_parent" - android:layout_height="48dip" - android:background="@color/background_main_toolbar" - android:orientation="horizontal" - android:baselineAligned="false" - android:visibility="visible"> - - <ImageButton - android:id="@+id/cancelFilter" - android:layout_width="wrap_content" - android:layout_height="fill_parent" - android:layout_gravity="left|center_vertical" - android:background="@android:color/transparent" - android:layout_weight=".1" - android:gravity="center" - android:src="@drawable/ic_menu_cancel_holo_light" - android:textSize="18dip"/> - - <ImageView - android:layout_width="2dp" - android:layout_height="fill_parent" - android:src="@drawable/filtershow_vertical_bar"/> - - <LinearLayout - android:id="@+id/panelAccessoryViewList" - android:layout_width="wrap_content" - android:layout_height="match_parent" - android:layout_weight="1" - android:orientation="horizontal" - android:visibility="visible"> - - <com.android.gallery3d.filtershow.editors.SwapButton - android:id="@+id/applyEffect" - android:layout_width="fill_parent" - android:layout_height="fill_parent" - android:layout_gravity="center" - android:background="@android:color/transparent" - android:text="@string/apply_effect" - android:textSize="18dip" - android:drawableEnd="@drawable/filtershow_menu_marker_rtl" - android:textAllCaps="true" - /> - - </LinearLayout> - - <ImageView - android:layout_width="2dp" - android:layout_height="fill_parent" - android:src="@drawable/filtershow_vertical_bar"/> - - <ImageButton - android:id="@+id/applyFilter" - android:layout_width="wrap_content" - android:layout_height="fill_parent" - android:layout_gravity="right|center_vertical" - android:layout_weight=".1" - android:background="@android:color/transparent" - android:gravity="center" - android:src="@drawable/ic_menu_done_holo_light" - android:textSize="18dip"/> - </LinearLayout> - - <FrameLayout android:id="@+id/state_panel_container" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:visibility="visible" /> - + android:layout_height="match_parent" + android:layout_weight="1" + android:gravity="center" + android:orientation="horizontal" + android:visibility="visible" > + + <com.android.gallery3d.filtershow.editors.SwapButton + android:id="@+id/applyEffect" + android:layout_width="@dimen/swap_button_width" + android:layout_height="@dimen/swap_button_height" + android:layout_gravity="center_vertical|center_horizontal" + android:background="@android:color/transparent" + android:drawableEnd="@drawable/spinner_triangle" + android:gravity="center" + android:text="@string/apply_effect" + android:textColor="#ffffff" + android:textSize="16sp" /> </LinearLayout> -</LinearLayout> + <ImageButton + android:id="@+id/applyFilter" + android:layout_width="wrap_content" + android:layout_height="fill_parent" + android:layout_gravity="right|center_vertical" + android:layout_weight=".1" + android:background="@android:color/transparent" + android:gravity="center" + android:src="@drawable/ic_menu_done_holo_light" + android:textSize="18dip" /> + +</LinearLayout>
\ No newline at end of file diff --git a/src/com/android/gallery3d/app/TimeLineDataLoader.java b/src/com/android/gallery3d/app/TimeLineDataLoader.java index b56304e39..6817b8871 100644..100755 --- a/src/com/android/gallery3d/app/TimeLineDataLoader.java +++ b/src/com/android/gallery3d/app/TimeLineDataLoader.java @@ -19,8 +19,6 @@ package com.android.gallery3d.app; import android.os.Handler; import android.os.Message; import android.os.Process; -import android.text.TextUtils; -import android.view.View; import com.android.gallery3d.common.Utils; import com.android.gallery3d.data.ContentListener; @@ -28,6 +26,7 @@ import com.android.gallery3d.data.MediaItem; import com.android.gallery3d.data.MediaObject; import com.android.gallery3d.data.MediaSet; import com.android.gallery3d.data.Path; +import com.android.gallery3d.data.ClusterAlbumSet; import com.android.gallery3d.ui.SynchronizedHandler; import java.util.ArrayList; @@ -35,12 +34,12 @@ import java.util.Arrays; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.FutureTask; -import java.util.Locale; -public class AlbumDataLoader { +public class TimeLineDataLoader { @SuppressWarnings("unused") - private static final String TAG = "AlbumDataAdapter"; + private static final String TAG = "TimeLineDataLoader"; private static final int DATA_CACHE_SIZE = 1000; + private boolean mNewVersion = false; private static final int MSG_LOAD_START = 1; private static final int MSG_LOAD_FINISH = 2; @@ -56,14 +55,17 @@ public class AlbumDataLoader { public static interface DataListener { public void onContentChanged(int index); public void onSizeChanged(int size); + public void onVersionChanged(); } + private int mActiveStart = 0; private int mActiveEnd = 0; private int mContentStart = 0; private int mContentEnd = 0; + private ArrayList<MediaItem> mTotalMediaItems; private final MediaSet mSource; private long mSourceVersion = MediaObject.INVALID_DATA_VERSION; @@ -78,9 +80,8 @@ public class AlbumDataLoader { // the data version on which last loading failed private long mFailedVersion = MediaObject.INVALID_DATA_VERSION; - public AlbumDataLoader(AbstractGalleryActivity context, MediaSet mediaSet) { + public TimeLineDataLoader(AbstractGalleryActivity context, MediaSet mediaSet) { mSource = mediaSet; - mData = new MediaItem[DATA_CACHE_SIZE]; mItemVersion = new long[DATA_CACHE_SIZE]; mSetVersion = new long[DATA_CACHE_SIZE]; @@ -121,15 +122,31 @@ public class AlbumDataLoader { mSource.removeContentListener(mSourceListener); } + + public MediaSet getMediaSet(int index) { + MediaSet mediaSet = ((ClusterAlbumSet)mSource).getAlbumFromindex(index); + return mediaSet; + } + public MediaItem get(int index) { - if (!isActive(index) - && View.LAYOUT_DIRECTION_LTR == TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault())) { + if (!isActive(index)) { return mSource.getMediaItem(index, 1).get(0); } return mData[index % mData.length]; } + public MediaItem getTimeLineTitleItem(int index) { + return ((ClusterAlbumSet)mSource).getTimelineTitleMediaItem(index); + } + + public int getTimeLineTitlesCount() { + return ((ClusterAlbumSet) mSource).getSubMediaSetCount(); + } + + public ArrayList<MediaItem> getAllMediaItems() { + return mTotalMediaItems; + } + public int getActiveStart() { return mActiveStart; } @@ -170,8 +187,6 @@ public class AlbumDataLoader { mContentStart = contentStart; mContentEnd = contentEnd; } - long[] itemVersion = mItemVersion; - long[] setVersion = mSetVersion; if (contentStart >= end || start >= contentEnd) { for (int i = start, n = end; i < n; ++i) { clearSlot(i % DATA_CACHE_SIZE); @@ -287,6 +302,9 @@ public class AlbumDataLoader { @Override public Void call() throws Exception { UpdateInfo info = mUpdateInfo; + if ( info.version != mSourceVersion) { + mNewVersion = true; + } mSourceVersion = info.version; if (mSize != info.size) { mSize = info.size; @@ -312,14 +330,16 @@ public class AlbumDataLoader { int index = i % DATA_CACHE_SIZE; mSetVersion[index] = info.version; MediaItem updateItem = items.get(i - info.reloadStart); - long itemVersion = updateItem.getDataVersion(); - if (mItemVersion[index] != itemVersion) { - mItemVersion[index] = itemVersion; - mData[index] = updateItem; - if (mDataListener != null && i >= mActiveStart && i < mActiveEnd) { - mDataListener.onContentChanged(i); + if (updateItem != null) { + long itemVersion = updateItem.getDataVersion(); + if (mItemVersion[index] != itemVersion) { + mItemVersion[index] = itemVersion; + mData[index] = updateItem; + if (mDataListener != null && i >= mActiveStart && i < mActiveEnd) { + mDataListener.onContentChanged(i); + } } - } + } } return null; } @@ -354,19 +374,17 @@ public class AlbumDataLoader { @Override public void run() { - Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); + Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); boolean updateComplete = false; while (mActive) { synchronized (this) { if (mActive && !mDirty && updateComplete) { updateLoading(false); if (mFailedVersion != MediaObject.INVALID_DATA_VERSION) { - Log.d(TAG, "reload pause"); } Utils.waitWithoutInterrupt(this); if (mActive && (mFailedVersion != MediaObject.INVALID_DATA_VERSION)) { - Log.d(TAG, "reload resume"); } continue; } @@ -376,7 +394,9 @@ public class AlbumDataLoader { long version = mSource.reload(); UpdateInfo info = executeAndWait(new GetUpdateInfo(version)); updateComplete = info == null; - if (updateComplete) continue; + if (updateComplete) { + continue; + } if (info.version != version) { info.size = mSource.getMediaItemCount(); info.version = version; @@ -384,7 +404,13 @@ public class AlbumDataLoader { if (info.reloadCount > 0) { info.items = mSource.getMediaItem(info.reloadStart, info.reloadCount); } + executeAndWait(new UpdateContent(info)); + if (mNewVersion) { + mNewVersion = false; + mTotalMediaItems = mSource.getMediaItem(0, mSource.getMediaItemCount()); + mDataListener.onVersionChanged(); + } } updateLoading(false); } diff --git a/src/com/android/gallery3d/app/TimeLinePage.java b/src/com/android/gallery3d/app/TimeLinePage.java index 932865a06..b3134ddcb 100644..100755 --- a/src/com/android/gallery3d/app/TimeLinePage.java +++ b/src/com/android/gallery3d/app/TimeLinePage.java @@ -1,4 +1,7 @@ /* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Not a Contribution + * * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,36 +22,44 @@ package com.android.gallery3d.app; import android.app.Activity; import android.content.Context; import android.content.Intent; -import android.drm.DrmHelper; +import android.content.res.Configuration; +import android.graphics.Color; import android.graphics.Rect; import android.net.Uri; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.provider.MediaStore; import android.text.TextUtils; +import android.util.TypedValue; +import android.view.Gravity; import android.view.HapticFeedbackConstants; import android.view.Menu; import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.RelativeLayout; +import android.widget.TextView; import android.widget.Toast; -import com.android.gallery3d.R; import com.android.gallery3d.common.Utils; +import com.android.gallery3d.data.ClusterAlbum; import com.android.gallery3d.data.DataManager; import com.android.gallery3d.data.MediaDetails; import com.android.gallery3d.data.MediaItem; import com.android.gallery3d.data.MediaObject; import com.android.gallery3d.data.MediaSet; import com.android.gallery3d.data.Path; +import com.android.gallery3d.data.ClusterAlbumSet; import com.android.gallery3d.filtershow.crop.CropActivity; import com.android.gallery3d.filtershow.crop.CropExtras; import com.android.gallery3d.glrenderer.FadeTexture; import com.android.gallery3d.glrenderer.GLCanvas; import com.android.gallery3d.ui.ActionModeHandler; import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener; -import com.android.gallery3d.ui.AlbumSlotRenderer; import com.android.gallery3d.ui.DetailsHelper; import com.android.gallery3d.ui.DetailsHelper.CloseListener; import com.android.gallery3d.ui.GLRoot; @@ -56,25 +67,26 @@ import com.android.gallery3d.ui.GLView; import com.android.gallery3d.ui.PhotoFallbackEffect; import com.android.gallery3d.ui.RelativePosition; import com.android.gallery3d.ui.SelectionManager; -import com.android.gallery3d.ui.SlotView; import com.android.gallery3d.ui.SynchronizedHandler; +import com.android.gallery3d.ui.TimeLineSlotRenderer; +import com.android.gallery3d.ui.TimeLineSlotView; import com.android.gallery3d.util.Future; import com.android.gallery3d.util.GalleryUtils; -import com.android.gallery3d.util.MediaSetUtils; +import com.android.gallery3d.R; +import java.lang.ref.WeakReference; +import java.util.ArrayList; import java.util.Locale; -public class AlbumPage extends ActivityState implements GalleryActionBar.ClusterRunner, - SelectionManager.SelectionListener, MediaSet.SyncListener, GalleryActionBar.OnAlbumModeSelectedListener { - @SuppressWarnings("unused") - private static final String TAG = "AlbumPage"; +public class TimeLinePage extends ActivityState implements + GalleryActionBar.ClusterRunner, SelectionManager.SelectionListener, + MediaSet.SyncListener, GalleryActionBar.OnAlbumModeSelectedListener { + + private static final String TAG = "TimeLinePage"; public static final String KEY_MEDIA_PATH = "media-path"; - public static final String KEY_PARENT_MEDIA_PATH = "parent-media-path"; - public static final String KEY_SET_CENTER = "set-center"; public static final String KEY_AUTO_SELECT_ALL = "auto-select-all"; public static final String KEY_SHOW_CLUSTER_MENU = "cluster-menu"; - public static final String KEY_EMPTY_ALBUM = "empty-album"; public static final String KEY_RESUME_ANIMATION = "resume_animation"; private static final int REQUEST_SLIDESHOW = 1; @@ -86,23 +98,16 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster private static final float USER_DISTANCE_METER = 0.3f; - // Data cache size, equal to AlbumDataLoader.DATA_CACHE_SIZE - private static final int DATA_CACHE_SIZE = 256; - private boolean mIsActive = false; - private AlbumSlotRenderer mAlbumView; + private TimeLineSlotRenderer mAlbumView; private Path mMediaSetPath; - private String mParentMediaSetString; - private SlotView mSlotView; - - private AlbumDataLoader mAlbumDataAdapter; - + private TimeLineSlotView mSlotView; + private TimeLineDataLoader mAlbumDataAdapter; protected SelectionManager mSelectionManager; - private boolean mGetContent; private boolean mShowClusterMenu; - private ActionModeHandler mActionModeHandler; + protected ActionModeHandler mActionModeHandler; private int mFocusIndex = 0; private DetailsHelper mDetailsHelper; private MyDetailsSource mDetailsSource; @@ -112,7 +117,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster private Future<Integer> mSyncTask = null; private boolean mLaunchedFromPhotoPage; private boolean mInCameraApp; - private boolean mInCameraAndWantQuitOnPause; + private TextView tvEmptyAlbum; private int mLoadingBits = 0; private boolean mInitialSynced = false; @@ -126,26 +131,30 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster private PhotoFallbackEffect mResumeEffect; private PhotoFallbackEffect.PositionProvider mPositionProvider = new PhotoFallbackEffect.PositionProvider() { - @Override - public Rect getPosition(int index) { - Rect rect = mSlotView.getSlotRect(index); - Rect bounds = mSlotView.bounds(); - rect.offset(bounds.left - mSlotView.getScrollX(), - bounds.top - mSlotView.getScrollY()); - return rect; - } + @Override + public Rect getPosition(int index) { + Rect rect = mSlotView.getSlotRect(index); + Rect bounds = mSlotView.bounds(); + rect.offset(bounds.left - mSlotView.getScrollX(), + bounds.top - mSlotView.getScrollY()); + return rect; + } + + @Override + public int getItemIndex(Path path) { + int start = mSlotView.getVisibleStart(); + int end = mSlotView.getVisibleEnd(); + for (int i = start; i < end; ++i) { + MediaItem item = mAlbumDataAdapter.get(i); + if (item != null && item.getPath() == path) return i; + } + return -1; + } + }; + + private Button mCameraButton; + private boolean mShowedEmptyToastForSelf = false; - @Override - public int getItemIndex(Path path) { - int start = mSlotView.getVisibleStart(); - int end = mSlotView.getVisibleEnd(); - for (int i = start; i < end; ++i) { - MediaItem item = mAlbumDataAdapter.get(i); - if (item != null && item.getPath() == path) return i; - } - return -1; - } - }; @Override protected int getBackgroundColorId() { @@ -160,8 +169,14 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster boolean changed, int left, int top, int right, int bottom) { int slotViewTop = mActivity.getGalleryActionBar().getHeight(); + int padding =0 ; + if((right - left) > (bottom - top)) { + padding = (int) mActivity.getResources().getDimension(R.dimen.timeline_land_margin); + } else { + padding = (int) mActivity.getResources().getDimension(R.dimen.timeline_port_margin); + } int slotViewBottom = bottom - top; - int slotViewRight = right - left; + int slotViewRight = right - left - padding; if (mShowDetails) { mDetailsHelper.layout(left, slotViewTop, right, bottom); @@ -171,7 +186,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster // Set the mSlotView as a reference point to the open animation mOpenCenter.setReferencePosition(0, slotViewTop); - mSlotView.layout(0, slotViewTop, slotViewRight, slotViewBottom); + mSlotView.layout(padding, slotViewTop, slotViewRight, slotViewBottom); GalleryUtils.setViewPointMatrix(mMatrix, (right - left) / 2, (bottom - top) / 2, -mUserDistance); } @@ -215,12 +230,10 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster mSelectionManager.leaveSelectionMode(); } else { if(mLaunchedFromPhotoPage) { - mActivity.getTransitionStore().putIfNotPresent( - PhotoPage.KEY_ALBUMPAGE_TRANSITION, - PhotoPage.MSG_ALBUMPAGE_RESUMED); + mActivity.getTransitionStore().putIfNotPresent( + PhotoPage.KEY_ALBUMPAGE_TRANSITION, + PhotoPage.MSG_ALBUMPAGE_RESUMED); } - // TODO: fix this regression - // mAlbumView.savePositions(PositionRepository.getInstance(mActivity)); if (mInCameraApp) { super.onBackPressed(); } else { @@ -232,14 +245,8 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster private void onUpPressed() { if (mInCameraApp) { GalleryUtils.startGalleryActivity(mActivity); - } else if (mActivity.getStateManager().getStateCount() > 1) { + } else super.onBackPressed(); - } else if (mParentMediaSetString != null) { - Bundle data = new Bundle(getData()); - data.putString(AlbumSetPage.KEY_MEDIA_PATH, mParentMediaSetString); - mActivity.getStateManager().switchState( - this, AlbumSetPage.class, data); - } } private void onDown(int index) { @@ -255,35 +262,32 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster } } - private void onSingleTapUp(int slotIndex) { + private void onSingleTapUp(int slotIndex , boolean isTitle) { if (!mIsActive) return; - - if (mSelectionManager.inSelectionMode()) { - MediaItem item = mAlbumDataAdapter.get(slotIndex); - if (item == null) return; // Item not ready yet, ignore the click - mSelectionManager.toggle(item.getPath()); - mSlotView.invalidate(); - } else { - // Render transition in pressed state - mAlbumView.setPressedIndex(slotIndex); - mAlbumView.setPressedUp(); - mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_PHOTO, slotIndex, 0), - FadeTexture.DURATION); - } + if (mSelectionManager.inSelectionMode()) { + if(isTitle){ + MediaSet targetSet = mAlbumDataAdapter.getMediaSet(slotIndex); + if (targetSet == null) return; + ArrayList<Path> paths = ((ClusterAlbum)targetSet).getMediaItems(); + if (paths == null || paths.size() <= 0) return; + mSelectionManager.toggleTimeLineSet(paths); + mSlotView.invalidate(); + } else { + MediaItem item = mAlbumDataAdapter.get(slotIndex); + if (item == null) return; // Item not ready yet, ignore the click + mSelectionManager.toggle(item.getPath()); + mSlotView.invalidate(); + } + } else if(!isTitle){ + // Render transition in pressed state + mAlbumView.setPressedIndex(slotIndex); + mAlbumView.setPressedUp(); + mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_PHOTO, slotIndex, 0), + FadeTexture.DURATION); + } } private void pickPhoto(int slotIndex) { - if ((View.LAYOUT_DIRECTION_RTL == TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault())) - && !mGetContent) { - // Fetch corresponding slotIndex from another side, (RTL) - if (slotIndex > DATA_CACHE_SIZE / 2 - && slotIndex < mAlbumDataAdapter.size() - DATA_CACHE_SIZE / 2) { - slotIndex = mAlbumDataAdapter.size() - slotIndex - 2; - } else { - slotIndex = mAlbumDataAdapter.size() - slotIndex - 1; - } - } pickPhoto(slotIndex, false); } @@ -297,30 +301,11 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster MediaItem item = mAlbumDataAdapter.get(slotIndex); - // Checking it is RTL or not - boolean isLayoutRtl = (View.LAYOUT_DIRECTION_RTL == TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault())) ? true : false; - - // When not RTL, return directly to ignore the click - if (!isLayoutRtl && item == null) { - return; - } - if (mGetContent) { - if (isLayoutRtl && item == null) { + if (item == null) return; // Item not ready yet, ignore the click - } - if (DrmHelper.isDrmFile(DrmHelper.getFilePath( - mActivity.getAndroidContext(), item.getContentUri()))) { - Toast.makeText(mActivity, R.string.no_permission_for_drm, - Toast.LENGTH_SHORT).show(); - return; - } onGetContent(item); } else if (mLaunchedFromPhotoPage) { - if (isLayoutRtl && item == null) { - return; // Item not ready yet, ignore the click - } TransitionStore transitions = mActivity.getTransitionStore(); transitions.put( PhotoPage.KEY_ALBUMPAGE_TRANSITION, @@ -328,31 +313,25 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex); onBackPressed(); } else { - // Get into the PhotoPage. - // mAlbumView.savePositions(PositionRepository.getInstance(mActivity)); + MediaSet targetset = mAlbumDataAdapter.getMediaSet(slotIndex); + if (targetset == null || item == null) return; + Bundle data = new Bundle(); - data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex); + data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex-1); + data.putString(PhotoPage.KEY_MEDIA_SET_PATH, + targetset.getPath().toString()); data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT, mSlotView.getSlotRect(slotIndex, mRootPane)); - data.putString(PhotoPage.KEY_MEDIA_SET_PATH, - mMediaSetPath.toString()); - - // Item not ready yet, don't pass the photo path to bundle - if (!isLayoutRtl && item != null) { - data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, - item.getPath().toString()); - } + data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, + item.getPath().toString()); + data.putBoolean(PhotoPage.KEY_FROM_TIMELINE_SCREEN, true); data.putInt(PhotoPage.KEY_ALBUMPAGE_TRANSITION, PhotoPage.MSG_ALBUMPAGE_STARTED); data.putBoolean(PhotoPage.KEY_START_IN_FILMSTRIP, startInFilmstrip); - data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, mMediaSet.isCameraRoll()); - if (startInFilmstrip) { - mActivity.getStateManager().switchState(this, FilmstripPage.class, data); - } else { - mActivity.getStateManager().startStateForResult( - SinglePhotoPage.class, REQUEST_PHOTO, data); - } + data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, targetset.isCameraRoll()); + mActivity.getStateManager().startStateForResult( + SinglePhotoPage.class, REQUEST_PHOTO, data); } } @@ -371,19 +350,29 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster activity.finish(); } else { Intent intent = new Intent(null, item.getContentUri()) - .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); activity.setResult(Activity.RESULT_OK, intent); activity.finish(); } } - public void onLongTap(int slotIndex) { + public void onLongTap(int slotIndex, boolean isTitle) { if (mGetContent) return; - MediaItem item = mAlbumDataAdapter.get(slotIndex); - if (item == null) return; - mSelectionManager.setAutoLeaveSelectionMode(true); - mSelectionManager.toggle(item.getPath()); - mSlotView.invalidate(); + if(isTitle){ + MediaSet targetSet = mAlbumDataAdapter.getMediaSet(slotIndex); + if (targetSet == null) return; + ArrayList<Path> paths = ((ClusterAlbum)targetSet).getMediaItems(); + if (paths == null || paths.size() <= 0) return; + mSelectionManager.setAutoLeaveSelectionMode(true); + mSelectionManager.toggleTimeLineSet(paths); + mSlotView.invalidate(); + } else { + MediaItem item = mAlbumDataAdapter.get(slotIndex); + if (item == null) return; + mSelectionManager.setAutoLeaveSelectionMode(true); + mSelectionManager.toggle(item.getPath()); + mSlotView.invalidate(); + } } @Override @@ -399,7 +388,6 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster GalleryActionBar.getClusterByTypeString(context, clusterType)); } - // mAlbumView.savePositions(PositionRepository.getInstance(mActivity)); mActivity.getStateManager().startStateForResult( AlbumSetPage.class, REQUEST_DO_ANIMATION, data); } @@ -413,7 +401,6 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster mGetContent = data.getBoolean(GalleryActivity.KEY_GET_CONTENT, false); mShowClusterMenu = data.getBoolean(KEY_SHOW_CLUSTER_MENU, false); mDetailsSource = new MyDetailsSource(); - Context context = mActivity.getAndroidContext(); if (data.getBoolean(KEY_AUTO_SELECT_ALL)) { mSelectionManager.selectAll(); @@ -441,6 +428,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster @Override protected void onResume() { super.onResume(); + mIsActive = true; mResumeEffect = mActivity.getTransitionStore().get(KEY_RESUME_ANIMATION); @@ -452,14 +440,6 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster setContentPane(mRootPane); - boolean enableHomeButton = (mActivity.getStateManager().getStateCount() > 1) | - mParentMediaSetString != null; - GalleryActionBar actionBar = mActivity.getGalleryActionBar(); - actionBar.setDisplayOptions(enableHomeButton, false); - if (!mGetContent) { - actionBar.enableAlbumModeMenu(GalleryActionBar.ALBUM_GRID_MODE_SELECTED, this); - } - // Set the reload bit here to prevent it exit this page in clearLoadingBit(). setLoadingBit(BIT_LOADING_RELOAD); mLoadingFailed = false; @@ -472,7 +452,6 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster setLoadingBit(BIT_LOADING_SYNC); mSyncTask = mMediaSet.requestSync(this); } - mInCameraAndWantQuitOnPause = mInCameraApp; } @Override @@ -488,15 +467,18 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster mAlbumDataAdapter.pause(); mAlbumView.pause(); DetailsHelper.pause(); - if (!mGetContent) { + /*if (!mGetContent) { mActivity.getGalleryActionBar().disableAlbumModeMenu(true); - } + }*/ if (mSyncTask != null) { mSyncTask.cancel(); mSyncTask = null; clearLoadingBit(BIT_LOADING_SYNC); } + + hideEmptyAlbumToast(); + hideCameraButton(); } @Override @@ -511,31 +493,31 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster private void initializeViews() { mSelectionManager = new SelectionManager(mActivity, false); mSelectionManager.setSelectionListener(this); - Config.AlbumPage config = Config.AlbumPage.get(mActivity); - mSlotView = new SlotView(mActivity, config.slotViewSpec); - mAlbumView = new AlbumSlotRenderer(mActivity, mSlotView, - mSelectionManager, config.placeholderColor); + Config.TimeLinePage config = Config.TimeLinePage.get(mActivity); + mSlotView = new TimeLineSlotView(mActivity, config.slotViewSpec); + mAlbumView = new TimeLineSlotRenderer(mActivity, mSlotView, + mSelectionManager, config.labelSpec, config.placeholderColor); mSlotView.setSlotRenderer(mAlbumView); mRootPane.addComponent(mSlotView); - mSlotView.setListener(new SlotView.SimpleListener() { + mSlotView.setListener(new TimeLineSlotView.SimpleListener() { @Override public void onDown(int index) { - AlbumPage.this.onDown(index); + TimeLinePage.this.onDown(index); } @Override public void onUp(boolean followedByLongPress) { - AlbumPage.this.onUp(followedByLongPress); + TimeLinePage.this.onUp(followedByLongPress); } @Override - public void onSingleTapUp(int slotIndex) { - AlbumPage.this.onSingleTapUp(slotIndex); + public void onSingleTapUp(int slotIndex, boolean isTitle) { + TimeLinePage.this.onSingleTapUp(slotIndex, isTitle); } @Override - public void onLongTap(int slotIndex) { - AlbumPage.this.onLongTap(slotIndex); + public void onLongTap(int slotIndex, boolean isTitle) { + TimeLinePage.this.onLongTap(slotIndex, isTitle); } }); mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager); @@ -549,13 +531,13 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster private void initializeData(Bundle data) { mMediaSetPath = Path.fromString(data.getString(KEY_MEDIA_PATH)); - mParentMediaSetString = data.getString(KEY_PARENT_MEDIA_PATH); mMediaSet = mActivity.getDataManager().getMediaSet(mMediaSetPath); if (mMediaSet == null) { Utils.fail("MediaSet is null. Path = %s", mMediaSetPath); } + mAlbumDataAdapter = new TimeLineDataLoader(mActivity, mMediaSet); mSelectionManager.setSourceMediaSet(mMediaSet); - mAlbumDataAdapter = new AlbumDataLoader(mActivity, mMediaSet); + //mSelectionManager.setAlbumDataAdapter(mAlbumDataAdapter); mAlbumDataAdapter.setLoadingListener(new MyLoadingListener()); mAlbumView.setModel(mAlbumDataAdapter); } @@ -592,17 +574,15 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster actionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits)); } else { inflator.inflate(R.menu.album, menu); - actionBar.setTitle(mMediaSet.getName()); + actionBar.setTitle(R.string.timeline_title); FilterUtils.setupMenuItems(actionBar, mMediaSetPath, true); - - menu.findItem(R.id.action_group_by).setVisible(mShowClusterMenu); - menu.findItem(R.id.action_camera).setVisible( - MediaSetUtils.isCameraSource(mMediaSetPath) - && GalleryUtils.isCameraAvailable(mActivity)); - + //menu.findItem(R.id.action_group_by).setVisible(mShowClusterMenu); + menu.findItem(R.id.action_camera).setVisible(GalleryUtils.isAnyCameraAvailable(mActivity)); + menu.findItem(R.id.action_sync_picasa_albums).setVisible(true); + menu.findItem(R.id.action_view_type).setVisible(false); } - actionBar.setSubtitle(null); + return true; } @@ -647,15 +627,10 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster mActivity.getStateManager().finishState(this); return true; case R.id.action_select: - mSelectionManager.setAutoLeaveSelectionMode(false); + mSelectionManager.setAutoLeaveSelectionMode(true); mSelectionManager.enterSelectionMode(); return true; - case R.id.action_group_by: { - mActivity.getGalleryActionBar().showClusterDialog(this); - return true; - } case R.id.action_slideshow: { - mInCameraAndWantQuitOnPause = false; Bundle data = new Bundle(); data.putString(SlideshowPage.KEY_SET_PATH, mMediaSetPath.toString()); @@ -684,7 +659,8 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster @Override protected void onStateResult(int request, int result, Intent data) { switch (request) { - case REQUEST_SLIDESHOW: { + case REQUEST_SLIDESHOW: + { // data could be null, if there is no images in the album if (data == null) return; mFocusIndex = data.getIntExtra(SlideshowPage.KEY_PHOTO_INDEX, 0); @@ -694,22 +670,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster case REQUEST_PHOTO: { if (data == null) return; mFocusIndex = data.getIntExtra(PhotoPage.KEY_RETURN_INDEX_HINT, 0); - if (View.LAYOUT_DIRECTION_RTL == TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault())) { - // Fetch corresponding index from another side, only in RTL - mFocusIndex = mAlbumDataAdapter.size() - mFocusIndex - 1; - // Prepare to jump to mFocusIndex position, only enabled in RTL - mSlotView.setIsFromPhotoPage(true); - } - - // Let picture of mFocusIndex visible mSlotView.makeSlotVisible(mFocusIndex); - - if (View.LAYOUT_DIRECTION_RTL == TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault())) { - // Reset variable - mSlotView.setIsFromPhotoPage(false); - } break; } case REQUEST_DO_ANIMATION: { @@ -725,14 +686,17 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster case SelectionManager.ENTER_SELECTION_MODE: { mActionModeHandler.startActionMode(); performHapticFeedback(HapticFeedbackConstants.LONG_PRESS); + ((GalleryActivity)mActivity).toggleNavDrawer(false); break; } case SelectionManager.LEAVE_SELECTION_MODE: { mActionModeHandler.finishActionMode(); + ((GalleryActivity)mActivity).toggleNavDrawer(true); mRootPane.invalidate(); break; } - case SelectionManager.SELECT_ALL_MODE: { + case SelectionManager.SELECT_ALL_MODE: + case SelectionManager.SELECT_NONE_MODE: { mActionModeHandler.updateSupportedOperation(); mRootPane.invalidate(); break; @@ -753,7 +717,7 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster public void onSyncDone(final MediaSet mediaSet, final int resultCode) { Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result=" + resultCode); - ((Activity) mActivity).runOnUiThread(new Runnable() { + mActivity.runOnUiThread(new Runnable() { @Override public void run() { GLRoot root = mActivity.getGLRoot(); @@ -793,11 +757,19 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster mLoadingBits &= ~loadTaskBit; if (mLoadingBits == 0 && mIsActive) { if (mAlbumDataAdapter.size() == 0) { - Intent result = new Intent(); - result.putExtra(KEY_EMPTY_ALBUM, true); - setStateResult(Activity.RESULT_OK, result); - mActivity.getStateManager().finishState(this); + mShowedEmptyToastForSelf = true; + showEmptyAlbumToast(Toast.LENGTH_LONG); + mSlotView.invalidate(); } + return; + } + // Hide the empty album toast if we are in the root instance of + // AlbumSetPage and the album is no longer empty (for instance, + // after a sync is completed and web albums have been synced) + if (mShowedEmptyToastForSelf) { + mShowedEmptyToastForSelf = false; + hideEmptyAlbumToast(); + //hideCameraButton(); } } @@ -821,19 +793,22 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster @Override public int size() { - return mAlbumDataAdapter.size(); + return mAlbumDataAdapter.size() - mAlbumDataAdapter.getTimeLineTitlesCount(); } @Override public int setIndex() { + if (mSelectionManager.getSelected(false) == null) return -1; Path id = mSelectionManager.getSelected(false).get(0); mIndex = mAlbumDataAdapter.findItem(id); - return mIndex; + int albumIndex = ((ClusterAlbumSet) mMediaSet).findTimelineAlbumIndex(mIndex); + return mIndex - albumIndex - 1; } @Override public MediaDetails getDetails() { // this relies on setIndex() being called beforehand + if (mIndex < 0) return null; MediaObject item = mAlbumDataAdapter.get(mIndex); if (item != null) { mAlbumView.setHighlightItemPath(item.getPath()); @@ -850,4 +825,61 @@ public class AlbumPage extends ActivityState implements GalleryActionBar.Cluster switchToFilmstrip(); } } + + private WeakReference<Toast> mEmptyAlbumToast = null; + + private void showCameraButton() { + if (mCameraButton == null && !setupCameraButton()) return; + mCameraButton.setVisibility(View.VISIBLE); + } + + private void hideCameraButton() { + if (mCameraButton == null) return; + mCameraButton.setVisibility(View.GONE); + } + + private boolean setupCameraButton() { + if (!GalleryUtils.isAnyCameraAvailable(mActivity)) return false; + RelativeLayout galleryRoot = (RelativeLayout)mActivity.findViewById(R.id.gallery_root); + if (galleryRoot == null) return false; + + mCameraButton = new Button(mActivity); + mCameraButton.setText(R.string.camera_label); + mCameraButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.frame_overlay_gallery_camera, 0, 0); + mCameraButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View arg0) { + GalleryUtils.startCameraActivity(mActivity); + } + }); + RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams( + RelativeLayout.LayoutParams.WRAP_CONTENT, + RelativeLayout.LayoutParams.WRAP_CONTENT); + lp.addRule(RelativeLayout.CENTER_IN_PARENT); + galleryRoot.addView(mCameraButton, lp); + return true; + } + + private void showEmptyAlbumToast(int toastLength) { + tvEmptyAlbum = new TextView(mActivity); + tvEmptyAlbum.setText(R.string.tvEmptyAlbum); + tvEmptyAlbum.setTextColor(Color.parseColor("#8A000000")); + tvEmptyAlbum.setGravity(Gravity.CENTER); + tvEmptyAlbum.setTextSize(TypedValue.COMPLEX_UNIT_SP,20); + RelativeLayout galleryRoot = (RelativeLayout) ((Activity) mActivity) + .findViewById(R.id.gallery_root); + RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams( + RelativeLayout.LayoutParams.WRAP_CONTENT, + RelativeLayout.LayoutParams.WRAP_CONTENT); + lp.addRule(RelativeLayout.CENTER_IN_PARENT); + galleryRoot.addView(tvEmptyAlbum, lp); + } + + private void hideEmptyAlbumToast() { + + if (tvEmptyAlbum != null) + { + tvEmptyAlbum.setVisibility(View.GONE); + } + } } diff --git a/src/com/android/gallery3d/data/TimeLineTitleMediaItem.java b/src/com/android/gallery3d/data/TimeLineTitleMediaItem.java index 1b0384548..cb24c669b 100644..100755 --- a/src/com/android/gallery3d/data/TimeLineTitleMediaItem.java +++ b/src/com/android/gallery3d/data/TimeLineTitleMediaItem.java @@ -1,4 +1,7 @@ /* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Not a Contribution + * * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,370 +19,67 @@ package com.android.gallery3d.data; -import android.annotation.TargetApi; -import android.content.ContentResolver; -import android.content.ContentValues; -import android.database.Cursor; -import android.drm.DrmHelper; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; import android.graphics.BitmapRegionDecoder; -import android.net.Uri; -import android.os.Build; -import android.provider.MediaStore.Images; -import android.provider.MediaStore.Images.ImageColumns; -import android.provider.MediaStore.MediaColumns; -import android.util.Log; -import com.android.gallery3d.app.GalleryApp; -import com.android.gallery3d.app.PanoramaMetadataSupport; -import com.android.gallery3d.common.ApiHelper; -import com.android.gallery3d.common.BitmapUtils; -import com.android.gallery3d.exif.ExifInterface; -import com.android.gallery3d.exif.ExifTag; -import com.android.gallery3d.filtershow.tools.SaveImage; +import com.android.gallery3d.common.Utils; +import com.android.gallery3d.ui.TimeLineTitleMaker; import com.android.gallery3d.util.GalleryUtils; import com.android.gallery3d.util.ThreadPool.Job; -import com.android.gallery3d.util.ThreadPool.JobContext; -import com.android.gallery3d.util.UpdateHelper; - -import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; - -// LocalImage represents an image in the local storage. -public class LocalImage extends LocalMediaItem { - private static final String TAG = "LocalImage"; - - static final Path ITEM_PATH = Path.fromString("/local/image/item"); - - // Must preserve order between these indices and the order of the terms in - // the following PROJECTION array. - private static final int INDEX_ID = 0; - private static final int INDEX_CAPTION = 1; - private static final int INDEX_MIME_TYPE = 2; - private static final int INDEX_LATITUDE = 3; - private static final int INDEX_LONGITUDE = 4; - private static final int INDEX_DATE_TAKEN = 5; - private static final int INDEX_DATE_ADDED = 6; - private static final int INDEX_DATE_MODIFIED = 7; - private static final int INDEX_DATA = 8; - private static final int INDEX_ORIENTATION = 9; - private static final int INDEX_BUCKET_ID = 10; - private static final int INDEX_SIZE = 11; - private static final int INDEX_WIDTH = 12; - private static final int INDEX_HEIGHT = 13; - static final String[] PROJECTION = { - ImageColumns._ID, // 0 - ImageColumns.TITLE, // 1 - ImageColumns.MIME_TYPE, // 2 - ImageColumns.LATITUDE, // 3 - ImageColumns.LONGITUDE, // 4 - ImageColumns.DATE_TAKEN, // 5 - ImageColumns.DATE_ADDED, // 6 - ImageColumns.DATE_MODIFIED, // 7 - ImageColumns.DATA, // 8 - ImageColumns.ORIENTATION, // 9 - ImageColumns.BUCKET_ID, // 10 - ImageColumns.SIZE, // 11 - "0", // 12 - "0" // 13 - }; +public class TimeLineTitleMediaItem extends MediaItem { + private static final String TAG = "TimeLineTitleMediaItem"; + private String mTitle; + private int mPhotoCount; + private int mVideoCount; - static { - updateWidthAndHeightProjection(); + public TimeLineTitleMediaItem(Path path) { + super(path); } - @TargetApi(Build.VERSION_CODES.JELLY_BEAN) - private static void updateWidthAndHeightProjection() { - if (ApiHelper.HAS_MEDIA_COLUMNS_WIDTH_AND_HEIGHT) { - PROJECTION[INDEX_WIDTH] = MediaColumns.WIDTH; - PROJECTION[INDEX_HEIGHT] = MediaColumns.HEIGHT; - } - } - - private final GalleryApp mApplication; - - public int rotation; - private PanoramaMetadataSupport mPanoramaMetadata = new PanoramaMetadataSupport(this); - - public LocalImage(Path path, GalleryApp application, Cursor cursor) { - super(path, nextVersionNumber()); - mApplication = application; - loadFromCursor(cursor); - } - - public LocalImage(Path path, GalleryApp application, int id) { - super(path, nextVersionNumber()); - mApplication = application; - ContentResolver resolver = mApplication.getContentResolver(); - Uri uri = Images.Media.EXTERNAL_CONTENT_URI; - Cursor cursor = LocalAlbum.getItemCursor(resolver, uri, PROJECTION, id); - if (cursor == null) { - throw new RuntimeException("cannot get cursor for: " + path); - } - try { - if (cursor.moveToNext()) { - loadFromCursor(cursor); - } else { - throw new RuntimeException("cannot find data for: " + path); - } - } finally { - cursor.close(); + public Job<Bitmap> requestTitle(int type, TimeLineTitleMaker maker) { + if (maker != null) { + return maker.requestTimeLineTitle(mTitle, mPhotoCount, mVideoCount); } + return null; } - private void loadFromCursor(Cursor cursor) { - id = cursor.getInt(INDEX_ID); - caption = cursor.getString(INDEX_CAPTION); - mimeType = cursor.getString(INDEX_MIME_TYPE); - latitude = cursor.getDouble(INDEX_LATITUDE); - longitude = cursor.getDouble(INDEX_LONGITUDE); - dateTakenInMs = cursor.getLong(INDEX_DATE_TAKEN); - dateAddedInSec = cursor.getLong(INDEX_DATE_ADDED); - dateModifiedInSec = cursor.getLong(INDEX_DATE_MODIFIED); - filePath = cursor.getString(INDEX_DATA); - rotation = cursor.getInt(INDEX_ORIENTATION); - bucketId = cursor.getInt(INDEX_BUCKET_ID); - fileSize = cursor.getLong(INDEX_SIZE); - width = cursor.getInt(INDEX_WIDTH); - height = cursor.getInt(INDEX_HEIGHT); + public void setTitle(String title) { + mTitle = title; } - - @Override - protected boolean updateFromCursor(Cursor cursor) { - UpdateHelper uh = new UpdateHelper(); - id = uh.update(id, cursor.getInt(INDEX_ID)); - caption = uh.update(caption, cursor.getString(INDEX_CAPTION)); - mimeType = uh.update(mimeType, cursor.getString(INDEX_MIME_TYPE)); - latitude = uh.update(latitude, cursor.getDouble(INDEX_LATITUDE)); - longitude = uh.update(longitude, cursor.getDouble(INDEX_LONGITUDE)); - dateTakenInMs = uh.update( - dateTakenInMs, cursor.getLong(INDEX_DATE_TAKEN)); - dateAddedInSec = uh.update( - dateAddedInSec, cursor.getLong(INDEX_DATE_ADDED)); - dateModifiedInSec = uh.update( - dateModifiedInSec, cursor.getLong(INDEX_DATE_MODIFIED)); - filePath = uh.update(filePath, cursor.getString(INDEX_DATA)); - rotation = uh.update(rotation, cursor.getInt(INDEX_ORIENTATION)); - bucketId = uh.update(bucketId, cursor.getInt(INDEX_BUCKET_ID)); - fileSize = uh.update(fileSize, cursor.getLong(INDEX_SIZE)); - width = uh.update(width, cursor.getInt(INDEX_WIDTH)); - height = uh.update(height, cursor.getInt(INDEX_HEIGHT)); - return uh.isUpdated(); - } - - @Override public Job<Bitmap> requestImage(int type) { - return new LocalImageRequest(mApplication, mPath, dateModifiedInSec, - type, filePath, mimeType); + return null; } - public static class LocalImageRequest extends ImageCacheRequest { - private String mLocalFilePath; - - LocalImageRequest(GalleryApp application, Path path, long timeModified, - int type, String localFilePath) { - super(application, path, timeModified, type, - MediaItem.getTargetSize(type)); - mLocalFilePath = localFilePath; - } - - LocalImageRequest(GalleryApp application, Path path, long timeModified, - int type, String localFilePath, String mimeType) { - super(application, path, timeModified, type, - MediaItem.getTargetSize(type),localFilePath, mimeType); - mLocalFilePath = localFilePath; - } - - @Override - public Bitmap onDecodeOriginal(JobContext jc, final int type) { - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inPreferredConfig = Bitmap.Config.ARGB_8888; - - if (DrmHelper.isDrmFile(mLocalFilePath)) { - return DecodeUtils.ensureGLCompatibleBitmap(DrmHelper - .getBitmap(mLocalFilePath, options)); - } - - int targetSize = MediaItem.getTargetSize(type); - - // try to decode from JPEG EXIF - if (type == MediaItem.TYPE_MICROTHUMBNAIL) { - ExifInterface exif = new ExifInterface(); - byte[] thumbData = null; - try { - exif.readExif(mLocalFilePath); - thumbData = exif.getThumbnail(); - } catch (FileNotFoundException e) { - Log.w(TAG, "failed to find file to read thumbnail: " + mLocalFilePath); - } catch (IOException e) { - Log.w(TAG, "failed to get thumbnail from: " + mLocalFilePath); - } - if (thumbData != null) { - Bitmap bitmap = DecodeUtils.decodeIfBigEnough( - jc, thumbData, options, targetSize); - if (bitmap != null) return bitmap; - } - } - - return DecodeUtils.decodeThumbnail(jc, mLocalFilePath, options, targetSize, type); - } - } - - @Override public Job<BitmapRegionDecoder> requestLargeImage() { - return new LocalLargeImageRequest(filePath); + Log.e(TAG, "Operation not supported"); + return null; } - public static class LocalLargeImageRequest - implements Job<BitmapRegionDecoder> { - String mLocalFilePath; - - public LocalLargeImageRequest(String localFilePath) { - mLocalFilePath = localFilePath; - } - - @Override - public BitmapRegionDecoder run(JobContext jc) { - if (DrmHelper.isDrmFile(mLocalFilePath)) { - return DrmHelper.createBitmapRegionDecoder(mLocalFilePath, - false); - } - - return DecodeUtils.createBitmapRegionDecoder(jc, mLocalFilePath, false); - } - } - - @Override - public int getSupportedOperations() { - int operation = SUPPORT_DELETE | SUPPORT_INFO; - if (DrmHelper.isDrmFile(getFilePath())) { - if (DrmHelper.isDrmFLBlocking(mApplication.getAndroidContext(), - getFilePath())) { - operation |= SUPPORT_SETAS; - } - operation |= SUPPORT_DRM_INFO | SUPPORT_FULL_IMAGE; - if (DrmHelper.isShareableDrmFile(getFilePath())) { - operation |= SUPPORT_SHARE; - } - } else { - operation = SUPPORT_DELETE | SUPPORT_SHARE | SUPPORT_CROP - | SUPPORT_SETAS | SUPPORT_PRINT | SUPPORT_INFO; - if (BitmapUtils.isSupportedByRegionDecoder(mimeType)) { - operation |= SUPPORT_FULL_IMAGE | SUPPORT_EDIT; - } - - if (BitmapUtils.isRotationSupported(mimeType)) { - operation |= SUPPORT_ROTATE; - } - - if (GalleryUtils.isValidLocation(latitude, longitude)) { - operation |= SUPPORT_SHOW_ON_MAP; - } - } - return operation; - } - - @Override - public void getPanoramaSupport(PanoramaSupportCallback callback) { - mPanoramaMetadata.getPanoramaSupport(mApplication, callback); - } - - @Override - public void clearCachedPanoramaSupport() { - mPanoramaMetadata.clearCachedValues(); - } - - @Override - public void delete() { - GalleryUtils.assertNotInRenderThread(); - Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI; - ContentResolver contentResolver = mApplication.getContentResolver(); - SaveImage.deleteAuxFiles(contentResolver, getContentUri()); - contentResolver.delete(baseUri, "_id=?", - new String[]{String.valueOf(id)}); - } - - @Override - public void rotate(int degrees) { - GalleryUtils.assertNotInRenderThread(); - Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI; - ContentValues values = new ContentValues(); - int rotation = (this.rotation + degrees) % 360; - if (rotation < 0) rotation += 360; - - if (mimeType.equalsIgnoreCase("image/jpeg")) { - ExifInterface exifInterface = new ExifInterface(); - ExifTag tag = exifInterface.buildTag(ExifInterface.TAG_ORIENTATION, - ExifInterface.getOrientationValueForRotation(rotation)); - if(tag != null) { - exifInterface.setTag(tag); - try { - exifInterface.forceRewriteExif(filePath); - fileSize = new File(filePath).length(); - values.put(Images.Media.SIZE, fileSize); - } catch (FileNotFoundException e) { - Log.w(TAG, "cannot find file to set exif: " + filePath); - } catch (IOException e) { - Log.w(TAG, "cannot set exif data: " + filePath); - } - } else { - Log.w(TAG, "Could not build tag: " + ExifInterface.TAG_ORIENTATION); - } - } - - values.put(Images.Media.ORIENTATION, rotation); - mApplication.getContentResolver().update(baseUri, values, "_id=?", - new String[]{String.valueOf(id)}); - } - - @Override - public Uri getContentUri() { - Uri baseUri = Images.Media.EXTERNAL_CONTENT_URI; - return baseUri.buildUpon().appendPath(String.valueOf(id)).build(); + public String getMimeType() { + return MediaObject.MEDIA_TYPE_IMAGE_STRING; } @Override public int getMediaType() { - if (DrmHelper.isDrmFile(getFilePath())) { - return MEDIA_TYPE_DRM_IMAGE; - } - - return MEDIA_TYPE_IMAGE; + return MediaObject.MEDIA_TYPE_TIMELINE_TITLE; } - @Override - public MediaDetails getDetails() { - MediaDetails details = super.getDetails(); - details.addDetail(MediaDetails.INDEX_ORIENTATION, Integer.valueOf(rotation)); - if (MIME_TYPE_JPEG.equals(mimeType)) { - // ExifInterface returns incorrect values for photos in other format. - // For example, the width and height of an webp images is always '0'. - MediaDetails.extractExifInfo(details, filePath); - } - return details; + public void setImageCount(int images) { + mPhotoCount = images; } - @Override - public int getRotation() { - return rotation; + public void setVideoCount(int video) { + mVideoCount = video; } - @Override public int getWidth() { - return width; + return 0; } - @Override public int getHeight() { - return height; + return 0; } - @Override - public String getFilePath() { - return filePath; - } } diff --git a/src/com/android/gallery3d/ui/TimeLineSlidingWindow.java b/src/com/android/gallery3d/ui/TimeLineSlidingWindow.java index fec7d1e92..0c44d46f3 100644 --- a/src/com/android/gallery3d/ui/TimeLineSlidingWindow.java +++ b/src/com/android/gallery3d/ui/TimeLineSlidingWindow.java @@ -20,21 +20,23 @@ import android.graphics.Bitmap; import android.os.Message; import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.app.AlbumDataLoader; +import com.android.gallery3d.app.TimeLineDataLoader; 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.data.TimeLineTitleMediaItem; 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 { +import java.util.ArrayList; + +public class TimeLineSlidingWindow implements TimeLineDataLoader.DataListener { @SuppressWarnings("unused") - private static final String TAG = "AlbumSlidingWindow"; + private static final String TAG = "TimeLineSlidingWindow"; private static final int MSG_UPDATE_ENTRY = 0; private static final int JOB_LIMIT = 2; @@ -42,6 +44,8 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { public static interface Listener { public void onSizeChanged(int size); public void onContentChanged(); + public void onVersionChanged(); + public int getTitleWidth(); } public static class AlbumEntry { @@ -54,47 +58,39 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { public TiledTexture bitmapTexture; public Texture content; private BitmapLoader contentLoader; - private PanoSupportListener mPanoSupportListener; + } - private final AlbumDataLoader mSource; + private final TimeLineDataLoader mSource; private final AlbumEntry mData[]; private final SynchronizedHandler mHandler; private final JobLimiter mThreadPool; private final TiledTexture.Uploader mTileUploader; private int mSize; - + private int mSlotWidth; 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; - } - } + private TimeLineTitleMaker mTitleMaker; + private int mTitleSize; + private int mTitleContentStart = 0; + private int mTitleContentEnd = 0; + private final int TITLE_CACHE_SIZE = 15; - public AlbumSlidingWindow(AbstractGalleryActivity activity, - AlbumDataLoader source, int cacheSize) { + public TimeLineSlidingWindow(AbstractGalleryActivity activity, + TimeLineDataLoader source, + int cacheSize, TimeLineSlotRenderer.LabelSpec labelSpec, + SelectionManager selection, TimeLineSlotView slotView) { source.setDataListener(this); mSource = source; mData = new AlbumEntry[cacheSize]; mSize = source.size(); - mHandler = new SynchronizedHandler(activity.getGLRoot()) { @Override public void handleMessage(Message message) { @@ -105,6 +101,7 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { mThreadPool = new JobLimiter(activity.getThreadPool(), JOB_LIMIT); mTileUploader = new TiledTexture.Uploader(activity.getGLRoot()); + mTitleMaker = new TimeLineTitleMaker(activity.getAndroidContext(), labelSpec, slotView); } public void setListener(Listener listener) { @@ -113,10 +110,10 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { public AlbumEntry get(int slotIndex) { if (!isActiveSlot(slotIndex)) { - Utils.fail("invalid slot: %s outsides (%s, %s)", - slotIndex, mActiveStart, mActiveEnd); + return null; } - return mData[slotIndex % mData.length]; + AlbumEntry item = mData[slotIndex % mData.length]; + return item; } public boolean isActiveSlot(int slotIndex) { @@ -162,7 +159,7 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { } public void setActiveWindow(int start, int end) { - if (!(start <= end && end - start <= mData.length && end <= mSize)) { + if (!(start <= end && end - start <= mData.length)) { Utils.fail("%s, %s, %s, %s", start, end, mData.length, mSize); } AlbumEntry data[] = mData; @@ -181,12 +178,17 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { private void uploadBgTextureInSlot(int index) { if (index < mContentEnd && index >= mContentStart) { AlbumEntry entry = mData[index % mData.length]; + if (entry == null) return; if (entry.bitmapTexture != null) { mTileUploader.addTexture(entry.bitmapTexture); } } } + public ArrayList<MediaItem> getAllMediaItems() { + return mSource.getAllMediaItems(); + } + private void updateTextureUploadQueue() { if (!mIsActive) return; mTileUploader.clear(); @@ -194,6 +196,9 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { // add foreground textures for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) { AlbumEntry entry = mData[i % mData.length]; + if (entry == null) { + continue; + } if (entry.bitmapTexture != null) { mTileUploader.addTexture(entry.bitmapTexture); } @@ -216,7 +221,7 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { private void requestNonactiveImages() { int range = Math.max( (mContentEnd - mActiveEnd), (mActiveStart - mContentStart)); - for (int i = 0 ;i < range; ++i) { + for (int i = 0; i < range; ++i) { requestSlotImage(mActiveEnd + i); requestSlotImage(mActiveStart - 1 - i); } @@ -226,11 +231,7 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { 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); + if (entry == null || entry.item == null) return false; entry.contentLoader.startLoad(); return entry.contentLoader.isRequestInProgress(); @@ -239,7 +240,7 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { private void cancelNonactiveImages() { int range = Math.max( (mContentEnd - mActiveEnd), (mActiveStart - mContentStart)); - for (int i = 0 ;i < range; ++i) { + for (int i = 0; i < range; ++i) { cancelSlotImage(mActiveEnd + i); cancelSlotImage(mActiveStart - 1 - i); } @@ -248,6 +249,7 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { private void cancelSlotImage(int slotIndex) { if (slotIndex < mContentStart || slotIndex >= mContentEnd) return; AlbumEntry item = mData[slotIndex % mData.length]; + if (item == null) return; if (item.contentLoader != null) item.contentLoader.cancelLoad(); } @@ -255,11 +257,14 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { 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(); + if (entry != null) { + 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; @@ -285,7 +290,7 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { } } - private class ThumbnailLoader extends BitmapLoader { + private class ThumbnailLoader extends BitmapLoader { private final int mSlotIndex; private final MediaItem mItem; @@ -296,8 +301,15 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { @Override protected Future<Bitmap> submitBitmapTask(FutureListener<Bitmap> l) { - return mThreadPool.submit( - mItem.requestImage(MediaItem.TYPE_MICROTHUMBNAIL), this); + if (mItem.getMediaType() != MediaObject.MEDIA_TYPE_TIMELINE_TITLE) { + return mThreadPool.submit( + mItem.requestImage(MediaItem.TYPE_MICROTHUMBNAIL), this); + } else if( mItem.getMediaType() == MediaObject.MEDIA_TYPE_TIMELINE_TITLE ){ + return mThreadPool.submit( + ((TimeLineTitleMediaItem) mItem).requestTitle( + MediaItem.TYPE_MICROTHUMBNAIL, mTitleMaker), this); + } + return null; } @Override @@ -308,18 +320,21 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { 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); - } + AlbumEntry entry = mData[mSlotIndex % mData.length]; + if (entry == null) return; + 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); + } + } } @@ -339,12 +354,18 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { freeSlotContent(index); prepareSlotContent(index); updateAllImageRequests(); + updateTextureUploadQueue(); if (mListener != null && isActiveSlot(index)) { mListener.onContentChanged(); } } } + @Override + public void onVersionChanged() { + mListener.onVersionChanged(); + } + public void resume() { mIsActive = true; TiledTexture.prepareResources(); @@ -362,4 +383,24 @@ public class AlbumSlidingWindow implements AlbumDataLoader.DataListener { freeSlotContent(i); } } + + public void onSlotSizeChanged(int width, int height) { + if (mSlotWidth == width) return; + + mSlotWidth = width; + + if (!mIsActive) return; + for (int slotIndex = mContentStart, n = mContentEnd; slotIndex < n; ++slotIndex) { + AlbumEntry entry = mData[slotIndex % mData.length]; + if (entry == null) { + continue; + } + if (entry.mediaType == MediaItem.MEDIA_TYPE_TIMELINE_TITLE) { + freeSlotContent(slotIndex); + prepareSlotContent(slotIndex); + } + } + updateAllImageRequests(); + updateTextureUploadQueue(); + } } diff --git a/src/com/android/gallery3d/ui/TimeLineSlotRenderer.java b/src/com/android/gallery3d/ui/TimeLineSlotRenderer.java index 5c1441ee9..5483647e7 100644 --- a/src/com/android/gallery3d/ui/TimeLineSlotRenderer.java +++ b/src/com/android/gallery3d/ui/TimeLineSlotRenderer.java @@ -16,8 +16,10 @@ package com.android.gallery3d.ui; + import com.android.gallery3d.app.AbstractGalleryActivity; -import com.android.gallery3d.app.AlbumDataLoader; +import com.android.gallery3d.app.TimeLineDataLoader; +import com.android.gallery3d.data.MediaItem; import com.android.gallery3d.data.MediaObject; import com.android.gallery3d.data.Path; import com.android.gallery3d.glrenderer.ColorTexture; @@ -26,21 +28,20 @@ import com.android.gallery3d.glrenderer.GLCanvas; import com.android.gallery3d.glrenderer.Texture; import com.android.gallery3d.glrenderer.TiledTexture; -public class AlbumSlotRenderer extends AbstractSlotRenderer { +import java.util.ArrayList; + +public class TimeLineSlotRenderer 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 TimeLineSlidingWindow mDataWindow; private final AbstractGalleryActivity mActivity; private final ColorTexture mWaitLoadingTexture; - private final SlotView mSlotView; + private final TimeLineSlotView mSlotView; private final SelectionManager mSelectionManager; private int mPressedIndex = -1; @@ -48,18 +49,29 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer { private Path mHighlightItemPath = null; private boolean mInSelectionMode; - private SlotFilter mSlotFilter; + private AlbumSlotRenderer.SlotFilter mSlotFilter; + private final LabelSpec mLabelSpec; - public AlbumSlotRenderer(AbstractGalleryActivity activity, SlotView slotView, - SelectionManager selectionManager, int placeholderColor) { + public static class LabelSpec { + + public int timeLineTitleHeight; + public int timeLineTitleFontSize; + public int timeLineTitleTextColor; + public int timeLineNumberTextColor; + public int timeLineTitleBackgroundColor; +} + public TimeLineSlotRenderer(AbstractGalleryActivity activity, TimeLineSlotView slotView, + SelectionManager selectionManager, LabelSpec labelSpec, + int placeholderColor) { super(activity); mActivity = activity; mSlotView = slotView; + mLabelSpec = labelSpec; mSelectionManager = selectionManager; mPlaceholderColor = placeholderColor; - mWaitLoadingTexture = new ColorTexture(mPlaceholderColor); mWaitLoadingTexture.setSize(1, 1); + } public void setPressedIndex(int index) { @@ -80,67 +92,19 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer { 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) { + protected 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) { - 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); - } else if ((entry.mediaType == MediaObject.MEDIA_TYPE_DRM_VIDEO) - || (entry.mediaType == MediaObject.MEDIA_TYPE_DRM_IMAGE)) { - drawDrmOverlay(canvas, width, height, entry.mediaType); - } - - if (entry.isPanorama) { - drawPanoramaIcon(canvas, width, height); - } - - renderRequestFlags |= renderOverlay(canvas, index, entry, width, height); - - return renderRequestFlags; + public ArrayList<MediaItem> getAllMediaItems() { + return mDataWindow.getAllMediaItems(); } - private int renderOverlay(GLCanvas canvas, int index, - AlbumSlidingWindow.AlbumEntry entry, int width, int height) { + protected int renderOverlay(GLCanvas canvas, int index, + TimeLineSlidingWindow.AlbumEntry entry, int width, int height) { int renderRequestFlags = 0; if (mPressedIndex == index) { if (mAnimatePressedUp) { @@ -155,13 +119,14 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer { } } else if ((entry.path != null) && (mHighlightItemPath == entry.path)) { drawSelectedFrame(canvas, width, height); - } else if (mInSelectionMode && mSelectionManager.isItemSelected(entry.path)) { + } else if (mInSelectionMode && entry.mediaType != MediaItem.MEDIA_TYPE_TIMELINE_TITLE + && mSelectionManager.isItemSelected(entry.path)) { drawSelectedFrame(canvas, width, height); } return renderRequestFlags; } - private class MyDataModelListener implements AlbumSlidingWindow.Listener { + protected class MyDataModelListener implements TimeLineSlidingWindow.Listener { @Override public void onContentChanged() { mSlotView.invalidate(); @@ -172,6 +137,17 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer { mSlotView.setSlotCount(size); mSlotView.invalidate(); } + + @Override + public void onVersionChanged() { + mSlotView.onVersionChanged(); + } + + @Override + public int getTitleWidth() { + return mSlotView.getTitleWidth(); + } + } public void resume() { @@ -196,10 +172,56 @@ public class AlbumSlotRenderer extends AbstractSlotRenderer { @Override public void onSlotSizeChanged(int width, int height) { - // Do nothing + if (mDataWindow != null) { + mDataWindow.onSlotSizeChanged(width, height); + } } - public void setSlotFilter(SlotFilter slotFilter) { + public void setSlotFilter(AlbumSlotRenderer.SlotFilter slotFilter) { mSlotFilter = slotFilter; } + + public void setModel(TimeLineDataLoader model) { + if (mDataWindow != null) { + mDataWindow.setListener(null); + mSlotView.setSlotCount(0); + mDataWindow = null; + } + if (model != null) { + mDataWindow = new TimeLineSlidingWindow(mActivity, model, CACHE_SIZE, mLabelSpec, + mSelectionManager, mSlotView); + mDataWindow.setListener(new MyDataModelListener()); + mSlotView.setSlotCount(model.size()); + } + } + + @Override + public int renderSlot(GLCanvas canvas, int index, int pass, int width, int height) { + if (mSlotFilter != null && !mSlotFilter.acceptSlot(index)) return 0; + + TimeLineSlidingWindow.AlbumEntry entry = mDataWindow.get(index); + int renderRequestFlags = 0; + Texture content = checkContentTexture(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, true, 0); + } + + renderRequestFlags |= renderOverlay(canvas, index, entry, width, height); + + return renderRequestFlags; + } } diff --git a/src/com/android/gallery3d/ui/TimeLineSlotView.java b/src/com/android/gallery3d/ui/TimeLineSlotView.java index eaf23f553..fc764570a 100644 --- a/src/com/android/gallery3d/ui/TimeLineSlotView.java +++ b/src/com/android/gallery3d/ui/TimeLineSlotView.java @@ -1,4 +1,7 @@ /* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Not a Contribution + * * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -13,12 +16,12 @@ * 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.text.TextUtils; +import android.util.Log; +import android.os.SystemProperties; import android.view.GestureDetector; import android.view.MotionEvent; import android.view.View; @@ -27,51 +30,47 @@ 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.data.MediaItem; +import com.android.gallery3d.data.MediaObject; import com.android.gallery3d.glrenderer.GLCanvas; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.Locale; -public class SlotView extends GLView { +public class TimeLineSlotView extends GLView { @SuppressWarnings("unused") - private static final String TAG = "SlotView"; + private static final String TAG = "TimeLineSlotView"; - private static final boolean WIDE = true; - private static final int INDEX_NONE = -1; + public static final int INDEX_NONE = -1; + private static final int mainKey = SystemProperties.getInt("qemu.hw.mainkeys", 1); public static final int RENDER_MORE_PASS = 1; public static final int RENDER_MORE_FRAME = 2; + private int mWidth = 0; + 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 onSingleTapUp(int index, boolean isTitle); + public void onLongTap(int index, boolean isTitle); 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 onSingleTapUp(int index, boolean isTitle) {} + @Override public void onLongTap(int index, boolean isTitle) {} @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; @@ -79,15 +78,12 @@ public class SlotView extends GLView { // 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 TimeLineSlotRenderer 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(); @@ -95,17 +91,15 @@ public class SlotView extends GLView { // Flag to check whether it is come from Photo Page. private boolean isFromPhotoPage = false; - public SlotView(AbstractGalleryActivity activity, Spec spec) { + public TimeLineSlotView(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) { + public void setSlotRenderer(TimeLineSlotRenderer slotDrawer) { mRenderer = slotDrawer; if (mRenderer != null) { - mRenderer.onSlotSizeChanged(mLayout.mSlotWidth, mLayout.mSlotHeight); mRenderer.onVisibleRangeChanged(getVisibleStart(), getVisibleEnd()); } } @@ -116,27 +110,28 @@ public class SlotView extends GLView { return; } Rect rect = mLayout.getSlotRect(index, mTempRect); - int position = WIDE - ? (rect.left + rect.right - getWidth()) / 2 - : (rect.top + rect.bottom - getHeight()) / 2; + int position = (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 visibleBegin = mScrollY; + int visibleLength = getHeight(); int visibleEnd = visibleBegin + visibleLength; - int slotBegin = WIDE ? rect.left : rect.top; - int slotEnd = WIDE ? rect.right : rect.bottom; + int slotBegin = rect.top; + int slotEnd = rect.bottom; int position = visibleBegin; if (visibleLength < slotEnd - slotBegin) { position = visibleBegin; } else if (slotBegin < visibleBegin) { position = slotBegin; - } else if (slotEnd > visibleEnd) { + } else if (slotEnd > visibleEnd && mainKey == 1) { position = slotEnd - visibleLength; + } else if (slotBegin > visibleEnd && mainKey == 0) { + position = slotBegin - visibleLength; } setScrollPosition(position); @@ -149,13 +144,15 @@ public class SlotView extends GLView { isFromPhotoPage = flag; } + public void setScrollPosition(int position) { - if (View.LAYOUT_DIRECTION_RTL == TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault()) - && position == 0 && !isFromPhotoPage) { - // If RTL and not from Photo Page, set position to max. - position = mLayout.getScrollLimit(); - } + /*if (View.LAYOUT_DIRECTION_RTL == TextUtils + .getLayoutDirectionFromLocale(Locale.getDefault()) + && position == 0 && !isFromPhotoPage) { + // If RTL and not from Photo Page, set position to max. + position = mLayout.getScrollLimit(); + }*/ + position = Utils.clamp(position, 0, mLayout.getScrollLimit()); mScroller.setPosition(position); updateScrollPosition(position, false); @@ -166,13 +163,9 @@ public class SlotView extends GLView { } @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; + mWidth = r - l; // Make sure we are still at a resonable scroll position after the size // is changed (like orientation change). We choose to keep the center @@ -182,7 +175,6 @@ public class SlotView extends GLView { mLayout.setSize(r - l, b - t); makeSlotVisible(visibleIndex); if (mOverscrollEffect == OVERSCROLL_3D) { - mPaper.setSize(r - l, b - t); } } @@ -199,12 +191,8 @@ public class SlotView extends GLView { } private void updateScrollPosition(int position, boolean force) { - if (!force && (WIDE ? position == mScrollX : position == mScrollY)) return; - if (WIDE) { - mScrollX = position; - } else { - mScrollY = position; - } + if (!force && (position == mScrollY)) return; + mScrollY = position; mLayout.setScrollPosition(position); onScrollPositionChanged(position); } @@ -220,7 +208,6 @@ public class SlotView extends GLView { @Override protected boolean onTouch(MotionEvent event) { - if (mUIListener != null) mUIListener.onUserInteraction(); mGestureDetector.onTouchEvent(event); switch (event.getAction()) { case MotionEvent.ACTION_DOWN: @@ -228,7 +215,6 @@ public class SlotView extends GLView { mScroller.forceFinished(); break; case MotionEvent.ACTION_UP: - mPaper.onRelease(); invalidate(); break; } @@ -239,15 +225,6 @@ public class SlotView extends GLView { 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]; @@ -264,13 +241,11 @@ public class SlotView extends GLView { 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. + // 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) { @@ -279,13 +254,13 @@ public class SlotView extends GLView { // I don't know why, but getCurrVelocity() can return NaN. if (!Float.isNaN(v)) { - mPaper.edgeReached(v); + //mPaper.edgeReached(v); } + //paperActive = mPaper.advanceAnimation(); } - paperActive = mPaper.advanceAnimation(); } - more |= paperActive; + //more |= paperActive; if (mAnimation != null) { more |= mAnimation.calculate(animTime); @@ -295,10 +270,10 @@ public class SlotView extends GLView { int requestCount = 0; int requestedSlot[] = expandIntArray(mRequestRenderSlots, - mLayout.mVisibleEnd - mLayout.mVisibleStart); + mLayout.getVisibleEnd() - mLayout.getVisibleStart()); - for (int i = mLayout.mVisibleEnd - 1; i >= mLayout.mVisibleStart; --i) { - int r = renderItem(canvas, i, 0, paperActive); + for (int i = mLayout.getVisibleEnd() - 1; i >= mLayout.getVisibleStart(); --i) { + int r = renderItem(canvas, i, 0, false); if ((r & RENDER_MORE_FRAME) != 0) more = true; if ((r & RENDER_MORE_PASS) != 0) requestedSlot[requestCount++] = i; } @@ -307,8 +282,8 @@ public class SlotView extends GLView { 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; + requestedSlot[i], pass, false); + if ((r & RENDER_MORE_FRAME) != 0) more = false; if ((r & RENDER_MORE_PASS) != 0) requestedSlot[newCount++] = i; } requestCount = newCount; @@ -318,27 +293,15 @@ public class SlotView extends GLView { 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 (rect == null) return 0; + canvas.translate(rect.left, rect.top, 0); if (mAnimation != null && mAnimation.isActive()) { mAnimation.apply(canvas, index, rect); } @@ -391,277 +354,6 @@ public class SlotView extends GLView { } } - // 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) { - if (View.LAYOUT_DIRECTION_RTL == TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault())) { - // If RTL, recalculate the columns and rows. - int count = ((mSlotCount + mUnitCount - 1) / mUnitCount); - col = count - index / mUnitCount - 1; - row = index % mUnitCount; - } else { - 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) { - if (View.LAYOUT_DIRECTION_RTL == TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault())) { - // If RTL, recalculate the position. - position = mContentLength > mWidth ? (mContentLength - position - mWidth) - : position; - position = Math.max(0, position); - } - 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); - if (View.LAYOUT_DIRECTION_RTL == TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault())) { - // If RTL, recalculate the absoluteX. - absoluteX = mContentLength > mWidth ? (mContentLength - absoluteX) : mWidth - - absoluteX; - } - 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; @@ -700,9 +392,7 @@ public class SlotView extends GLView { 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(); + mScroller.fling((int) -velocityY, 0, scrollLimit); invalidate(); return true; } @@ -711,11 +401,10 @@ public class SlotView extends GLView { 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()); + Math.round(distanceY), 0, mLayout.getScrollLimit()); if (mOverscrollEffect == OVERSCROLL_3D && overDistance != 0) { - mPaper.overScroll(overDistance); + //mPaper.overScroll(overDistance); } invalidate(); return true; @@ -725,9 +414,19 @@ public class SlotView extends GLView { 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; + RectSlot slot = mLayout.getRectSlotByPosition(e.getX(), e.getY()); + if (slot == null) { + return true; + } + int index = slot.slotIndex; + if (index != INDEX_NONE) { + if (slot.mediaType == MediaObject.MEDIA_TYPE_TIMELINE_TITLE) { + mListener.onSingleTapUp(index, true); + return true; + } + mListener.onSingleTapUp(index, false); + } + return true; } @Override @@ -736,8 +435,18 @@ public class SlotView extends GLView { if (mDownInScrolling) return; lockRendering(); try { - int index = mLayout.getSlotIndexByPosition(e.getX(), e.getY()); - if (index != INDEX_NONE) mListener.onLongTap(index); + RectSlot slot = mLayout.getRectSlotByPosition(e.getX(), e.getY()); + if (slot == null) return; + + int index = slot.slotIndex; + if (index != INDEX_NONE) { + if (slot.mediaType == MediaObject.MEDIA_TYPE_TIMELINE_TITLE) { + mListener.onLongTap(index, true); + + } else { + mListener.onLongTap(index, false); + } + } } finally { unlockRendering(); } @@ -758,10 +467,15 @@ public class SlotView extends GLView { mStartIndex = INDEX_NONE; } // Reset the scroll position to avoid scrolling over the updated limit. - setScrollPosition(WIDE ? mScrollX : mScrollY); + setScrollPosition(mScrollY); return changed; } + public void onVersionChanged() { + mLayout.createSlots(); + invalidate(); + } + public int getVisibleStart() { return mLayout.getVisibleStart(); } @@ -788,48 +502,286 @@ public class SlotView extends GLView { return r; } - private static class IntegerAnimation extends Animation { - private int mTarget; - private int mCurrent = 0; - private int mFrom = 0; - private boolean mEnabled = false; + public int getTitleWidth() { + return mWidth; + } + + // This Spec class is used to specify the size of each slot in the SlotView. + // There are two ways to do it: + // + // Specify colsLand, colsPort, 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 colsLand = -1; + public int colsPort = -1; + public int titleHeight = -1; + public int slotGapPort = -1; + public int slotGapLand = -1; + } + + public class Layout { + + private int mVisibleStart; + private int mVisibleEnd; + + public 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 ArrayList<Integer> mHeightList; + private HashMap<Integer, RectSlot> mMediaSlotMap; - public void setEnabled(boolean enabled) { - mEnabled = enabled; + public void setSlotSpec(TimeLineSlotView.Spec spec) { + mSpec = spec; } - public void startAnimateTo(int target) { - if (!mEnabled) { - mTarget = mCurrent = target; - return; + public boolean setSlotCount(int slotCount) { + if (slotCount == mSlotCount) return false; + mSlotCount = slotCount; + initLayoutParameters(); + updateVisibleSlotRange(); + return true; + } + + public Rect getSlotRect(int index, Rect rect) { + if (index >= mVisibleStart && index < mVisibleEnd && mVisibleEnd != 0) { + RectSlot slot = getRectSlot(index); + if (slot == null) { + return null; + } + return getSlotRect(slot, rect); } - if (target == mTarget) return; + return rect; + } - mFrom = mCurrent; - mTarget = target; - setDuration(180); - start(); + private void initLayoutParameters() { + mUnitCount = (mWidth > mHeight) ? mSpec.colsLand : mSpec.colsPort; + mSlotGap = (mWidth > mHeight) ? mSpec.slotGapLand: mSpec.slotGapPort; + mSlotWidth = Math.round((mWidth - (mUnitCount - 1) * mSlotGap) / mUnitCount); + mSlotHeight = mSlotWidth; + if (mRenderer != null) { + mRenderer.onSlotSizeChanged(mSlotWidth, mSlotHeight); + } } - public int get() { - return mCurrent; + private void setSize(int width, int height) { + mWidth = width; + mHeight = height; + initLayoutParameters(); + createSlots(); + updateVisibleSlotRange(); } - public int getTarget() { - return mTarget; + public void setScrollPosition(int position) { + if (mScrollPosition == position) return; + mScrollPosition = position; + updateVisibleSlotRange(); } - @Override - protected void onCalculate(float progress) { - mCurrent = Math.round(mFrom + progress * (mTarget - mFrom)); - if (progress == 1f) mEnabled = false; + private Rect getSlotRect(RectSlot slot, Rect rect) { + if (rect == null) { + Log.e(TAG, "LAYOUT: null rect passed"); + Utils.assertTrue(false); + } + int x = 0; + int y = 0; + int w = mSlotWidth; + int h = 0; + if (slot.mediaType == MediaObject.MEDIA_TYPE_TIMELINE_TITLE) { + x = 0; + y = slot.totalHeight - (mSpec.titleHeight); + w = mWidth; + h = mSpec.titleHeight; + } else { + x = slot.slotCol * (mSlotWidth + mSlotGap); + y = slot.totalHeight -(mSlotHeight); + w = mSlotWidth; + h = mSlotHeight; + } + rect.set(x, y, x + w, y + h); + return rect; + } + + private synchronized void updateVisibleSlotRange() { + int position = mScrollPosition; + if(mHeightList!= null && mHeightList.size()>0 ) { + int indexStart = Arrays.binarySearch(mHeightList.toArray(new Integer[0]), position); + int indexEnd = Arrays.binarySearch(mHeightList.toArray(new Integer[0]), position+mHeight); + if(indexStart<0) { + indexStart = (indexStart * (- 1)) - 1; + } if (indexEnd<0) { + indexEnd = (indexEnd * (- 1)) - 1; + } + int startSlotIndex = mHeightList.indexOf(mHeightList.get(indexStart)); + if(indexEnd> mHeightList.size()-1) { + indexEnd = mHeightList.size()-1; + } + int endSlotIndex = mHeightList.lastIndexOf(mHeightList.get(indexEnd)); + + + int endSlotIndexStr = mHeightList.indexOf(mHeightList.get(indexEnd)); + if(((endSlotIndex-endSlotIndexStr) % mUnitCount) == (mUnitCount-1) && (startSlotIndex>mUnitCount)) { + startSlotIndex= startSlotIndex-mUnitCount; + } + + setVisibleRange(startSlotIndex, Math.min(mSlotCount, endSlotIndex + 1)); + } + } + + 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) { + RectSlot slot = getRectSlotByPosition(x, y); + if (slot == null) return INDEX_NONE; + + return slot.slotIndex; + + } + + public RectSlot getRectSlotByPosition(float x, float y) { + int absoluteX = Math.round(x); + int absoluteY = Math.round(y) + mScrollPosition; + + if (absoluteX < 0 || absoluteY < 0) { + return null; + } + if (absoluteY > mContentLength) + return null; + + int columnIdx = absoluteX / (mSlotWidth + mSlotGap); + + RectSlot rectSlot; + + int index = Arrays.binarySearch(mHeightList.toArray(new Integer[0]), absoluteY); + if(index<0){ + index = (index*-1) -1; + } + if(index >= mHeightList.size()) { + index = mHeightList.size()-1; + } + int startIndex = mHeightList.indexOf(mHeightList.get(index)); + int maxIndex = mHeightList.lastIndexOf(mHeightList.get(index)); + if(mMediaSlotMap.get(startIndex).mediaType == MediaObject.MEDIA_TYPE_TIMELINE_TITLE) { + return mMediaSlotMap.get(startIndex); + } + for(int i= startIndex;(i< startIndex+mUnitCount) && (i<=maxIndex); i++) { + rectSlot = mMediaSlotMap.get(i); + if(rectSlot.slotCol== columnIdx) { + return rectSlot; + } + } + return null; + } + + public int getScrollLimit() { + if (mHeightList != null && mHeightList.size() > 0) { + return Math.max(0, mContentLength -mHeight); + } + return 0; + } + + + + public void createSlots() { + ArrayList<MediaItem> mediaItemlist = new ArrayList<MediaItem>(); + if (mRenderer != null) { + mediaItemlist = mRenderer.getAllMediaItems(); + } + if (mediaItemlist != null && mediaItemlist.size() > 0) { + if (mHeightList == null) { + mHeightList = new ArrayList<Integer>(); + } + if (mMediaSlotMap == null) { + mMediaSlotMap = new HashMap<Integer, RectSlot>(); + } + mHeightList.clear(); + mMediaSlotMap.clear(); + boolean isPrevTitle = false; + int j = 0; + int col = 0; + int totalHieght = 0; + for (int i = 0; i < mediaItemlist.size(); ++i) { + MediaItem info = mediaItemlist.get(i); + + if (info.getMediaType() == MediaObject.MEDIA_TYPE_TIMELINE_TITLE) { + totalHieght += (mSpec.titleHeight+mSlotGap); + isPrevTitle = true; + col =0; + } else { + if (isPrevTitle) { + j =0; + isPrevTitle = false; + } else { + ++j; + } + if(j%mUnitCount == 0) { + totalHieght += (mSlotHeight+mSlotGap); + col =0; + } else { + col = j%mUnitCount; + } + + } + mHeightList.add(totalHieght); + RectSlot rectslot = new RectSlot(info.getMediaType(), i, col, totalHieght); + mMediaSlotMap.put(rectslot.slotIndex, rectslot); + } + mContentLength = mHeightList.get(mHeightList.size() -1); + mSlotCount = mediaItemlist.size(); + } + updateVisibleSlotRange(); + } + + public RectSlot getRectSlot(int slotIndex) { + return mMediaSlotMap.get(slotIndex); } } - /** - * Get the SlotView's max scroll value. - */ - public int getScrollLimit() { - return mLayout.getScrollLimit(); + + + public static class RectSlot { + public int mediaType; + public int slotIndex; + public int slotCol; + public int totalHeight; + + public RectSlot(int type, int index, int col, int height) { + mediaType = type; + slotIndex = index; + slotCol = col; + totalHeight = height; + } } } diff --git a/src/com/android/gallery3d/ui/TimeLineTitleMaker.java b/src/com/android/gallery3d/ui/TimeLineTitleMaker.java index 3ac3bb7fe..45acdef87 100644..100755 --- a/src/com/android/gallery3d/ui/TimeLineTitleMaker.java +++ b/src/com/android/gallery3d/ui/TimeLineTitleMaker.java @@ -1,4 +1,7 @@ /* + * Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Not a Contribution + * * Copyright (C) 2012 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,221 +22,135 @@ 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 android.view.View; -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; +import com.android.photos.data.GalleryBitmapPool; +import com.android.gallery3d.R; -import java.util.Locale; +public class TimeLineTitleMaker { -public class AlbumLabelMaker { + private final String TAG = "TimelineTitleMaker"; private static final int BORDER_SIZE = 0; - private final AlbumSetSlotRenderer.LabelSpec mSpec; + private final TimeLineSlotRenderer.LabelSpec mSpec; private final TextPaint mTitlePaint; private final TextPaint mCountPaint; private final Context mContext; + private final TimeLineSlotView mTimeLineSlotView; - 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) { + public TimeLineTitleMaker(Context context, TimeLineSlotRenderer.LabelSpec spec, TimeLineSlotView slotView) { 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; + mTimeLineSlotView = slotView; + mTitlePaint = getTextPaint(spec.timeLineTitleFontSize, spec.timeLineTitleTextColor , true); + mCountPaint = getTextPaint(spec.timeLineTitleFontSize, spec.timeLineNumberTextColor, true); } - 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) { + 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); + paint.setTypeface(Typeface.SANS_SERIF); 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); + public ThreadPool.Job<Bitmap> requestTimeLineTitle( String title, + int photoCount, int videoCount) { + return new TimeLineTitle(title,photoCount, videoCount, mContext ); } 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); - } + int x, int y, String text, int lengthLimit, TextPaint 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) { + private class TimeLineTitle implements ThreadPool.Job<Bitmap> { + private String mTitle; + private int mVideoCount; + private int mImageCount; + private Context mContext; + public TimeLineTitle(String title, int imageCount, int videoCount, Context context) { mTitle = title; - mCount = count; - mSourceType = sourceType; + mImageCount = imageCount; + mVideoCount = videoCount; + mContext = context; + } @Override public Bitmap run(JobContext jc) { - AlbumSetSlotRenderer.LabelSpec s = mSpec; - - String title = mTitle; - String count = mCount; - Bitmap icon = getOverlayAlbumIcon(mSourceType); + TimeLineSlotRenderer.LabelSpec spec = mSpec; Bitmap bitmap; - int labelWidth; - + int width = mTimeLineSlotView.getTitleWidth(); + int height= spec.timeLineTitleHeight; synchronized (this) { - labelWidth = mLabelWidth; - bitmap = GalleryBitmapPool.getInstance().get(mBitmapWidth, mBitmapHeight); + bitmap = GalleryBitmapPool.getInstance().get(width, height); } - if (bitmap == null) { int borders = 2 * BORDER_SIZE; - bitmap = Bitmap.createBitmap(labelWidth + borders, - s.labelBackgroundHeight + borders, Config.ARGB_8888); + bitmap = Bitmap.createBitmap(width + borders, + height + borders, Config.ARGB_8888); + } + if (bitmap == null) { + return null; } - 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.drawColor(mSpec.timeLineTitleBackgroundColor, PorterDuff.Mode.SRC); canvas.translate(BORDER_SIZE, BORDER_SIZE); - if (View.LAYOUT_DIRECTION_RTL == TextUtils - .getLayoutDirectionFromLocale(Locale.getDefault())) {// RTL - // draw title - if (jc.isCancelled()) return null; - int strLength = (int) mTitlePaint.measureText(title); - int x = labelWidth - (s.leftMargin + s.iconSize) - strLength; - // 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 = s.leftMargin + 10;// plus 10 to get a much bigger margin - 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(labelWidth - s.leftMargin - s.iconSize, - (s.labelBackgroundHeight - - Math.round(scale * icon.getHeight())) / 2f); - canvas.scale(scale, scale); - canvas.drawBitmap(icon, 0, 0, null); + + StringBuilder sb = new StringBuilder(); + if(mImageCount != 0) { + sb.append(mContext.getResources().getQuantityString(R.plurals.number_of_photos, mImageCount, mImageCount)); + if(mVideoCount!=0) { + sb.append(mContext.getResources().getQuantityString( + R.plurals.number_of_videos, mVideoCount, mVideoCount)); } - } else { // LTR - // 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); + } else { + if(mVideoCount != 0) { + sb.append(mContext.getResources().getQuantityString( + R.plurals.number_of_videos, mVideoCount, mVideoCount)); } } + String countString = sb.toString(); + + if (jc.isCancelled()) return null; + + int x; + int y = 0; + if (mTitle != null) { + mTitle = mTitle.toUpperCase(); + x = 16; + y = (height/2)-14; + drawText(canvas, x, y, mTitle, width-x, mTitlePaint); + } + + if (countString != null) { + y = (height/2)-14; + x = width - countString.length()- 100; + drawText(canvas, x, y, countString, + width - x, mCountPaint); + } return bitmap; } } - - public void recycleLabel(Bitmap label) { - GalleryBitmapPool.getInstance().put(label); - } } |
