blob: a9abc81fff972724d6bcff234e695c2da56ae269 [file] [log] [blame]
Ravi Banuri7a41c372015-10-19 16:03:03 +05301/*
Ravi Banuric963ee82015-10-20 19:41:58 +05302 * Copyright (c) 2015, The Linux Foundation. All rights reserved.
3 * Not a Contribution
4 *
Ravi Banuri7a41c372015-10-19 16:03:03 +05305 * Copyright (C) 2010 The Android Open Source Project
6 *
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 */
19
20package com.android.gallery3d.app;
21
22import android.app.Activity;
23import android.content.Context;
24import android.content.Intent;
Ravi Banuric963ee82015-10-20 19:41:58 +053025import android.content.res.Configuration;
26import android.graphics.Color;
Ravi Banuri7a41c372015-10-19 16:03:03 +053027import android.graphics.Rect;
28import android.net.Uri;
Ravi Banuric963ee82015-10-20 19:41:58 +053029import android.os.AsyncTask;
Ravi Banuri7a41c372015-10-19 16:03:03 +053030import android.os.Bundle;
31import android.os.Handler;
32import android.os.Message;
33import android.provider.MediaStore;
34import android.text.TextUtils;
Ravi Banuric963ee82015-10-20 19:41:58 +053035import android.util.TypedValue;
36import android.view.Gravity;
Ravi Banuri7a41c372015-10-19 16:03:03 +053037import android.view.HapticFeedbackConstants;
38import android.view.Menu;
39import android.view.MenuInflater;
40import android.view.MenuItem;
41import android.view.View;
Ravi Banuric963ee82015-10-20 19:41:58 +053042import android.view.View.OnClickListener;
43import android.widget.Button;
44import android.widget.RelativeLayout;
45import android.widget.TextView;
Ravi Banuri7a41c372015-10-19 16:03:03 +053046import android.widget.Toast;
47
Ravi Banuri7a41c372015-10-19 16:03:03 +053048import com.android.gallery3d.common.Utils;
Ravi Banuric963ee82015-10-20 19:41:58 +053049import com.android.gallery3d.data.ClusterAlbum;
Ravi Banuri7a41c372015-10-19 16:03:03 +053050import com.android.gallery3d.data.DataManager;
51import com.android.gallery3d.data.MediaDetails;
52import com.android.gallery3d.data.MediaItem;
53import com.android.gallery3d.data.MediaObject;
54import com.android.gallery3d.data.MediaSet;
55import com.android.gallery3d.data.Path;
Ravi Banuric963ee82015-10-20 19:41:58 +053056import com.android.gallery3d.data.ClusterAlbumSet;
Ravi Banuri7a41c372015-10-19 16:03:03 +053057import com.android.gallery3d.filtershow.crop.CropActivity;
58import com.android.gallery3d.filtershow.crop.CropExtras;
59import com.android.gallery3d.glrenderer.FadeTexture;
60import com.android.gallery3d.glrenderer.GLCanvas;
61import com.android.gallery3d.ui.ActionModeHandler;
62import com.android.gallery3d.ui.ActionModeHandler.ActionModeListener;
Ravi Banuri7a41c372015-10-19 16:03:03 +053063import com.android.gallery3d.ui.DetailsHelper;
64import com.android.gallery3d.ui.DetailsHelper.CloseListener;
65import com.android.gallery3d.ui.GLRoot;
66import com.android.gallery3d.ui.GLView;
67import com.android.gallery3d.ui.PhotoFallbackEffect;
68import com.android.gallery3d.ui.RelativePosition;
69import com.android.gallery3d.ui.SelectionManager;
Ravi Banuri7a41c372015-10-19 16:03:03 +053070import com.android.gallery3d.ui.SynchronizedHandler;
Ravi Banuric963ee82015-10-20 19:41:58 +053071import com.android.gallery3d.ui.TimeLineSlotRenderer;
72import com.android.gallery3d.ui.TimeLineSlotView;
Ravi Banuri7a41c372015-10-19 16:03:03 +053073import com.android.gallery3d.util.Future;
74import com.android.gallery3d.util.GalleryUtils;
Likai Dingc83b5b72016-05-25 14:48:41 +080075import org.codeaurora.gallery.R;
Ravi Banuri7a41c372015-10-19 16:03:03 +053076
Ravi Banuric963ee82015-10-20 19:41:58 +053077import java.lang.ref.WeakReference;
78import java.util.ArrayList;
Ravi Banuri7a41c372015-10-19 16:03:03 +053079import java.util.Locale;
80
Ravi Banuric963ee82015-10-20 19:41:58 +053081public class TimeLinePage extends ActivityState implements
82 GalleryActionBar.ClusterRunner, SelectionManager.SelectionListener,
83 MediaSet.SyncListener, GalleryActionBar.OnAlbumModeSelectedListener {
84
85 private static final String TAG = "TimeLinePage";
Ravi Banuri7a41c372015-10-19 16:03:03 +053086
87 public static final String KEY_MEDIA_PATH = "media-path";
Ravi Banuri7a41c372015-10-19 16:03:03 +053088 public static final String KEY_AUTO_SELECT_ALL = "auto-select-all";
89 public static final String KEY_SHOW_CLUSTER_MENU = "cluster-menu";
Ravi Banuri7a41c372015-10-19 16:03:03 +053090 public static final String KEY_RESUME_ANIMATION = "resume_animation";
91
92 private static final int REQUEST_SLIDESHOW = 1;
93 public static final int REQUEST_PHOTO = 2;
94 private static final int REQUEST_DO_ANIMATION = 3;
95
96 private static final int BIT_LOADING_RELOAD = 1;
97 private static final int BIT_LOADING_SYNC = 2;
98
99 private static final float USER_DISTANCE_METER = 0.3f;
100
Ravi Banuri7a41c372015-10-19 16:03:03 +0530101 private boolean mIsActive = false;
Ravi Banuric963ee82015-10-20 19:41:58 +0530102 private TimeLineSlotRenderer mAlbumView;
Ravi Banuri7a41c372015-10-19 16:03:03 +0530103 private Path mMediaSetPath;
Ravi Banuric963ee82015-10-20 19:41:58 +0530104 private TimeLineSlotView mSlotView;
105 private TimeLineDataLoader mAlbumDataAdapter;
Ravi Banuri7a41c372015-10-19 16:03:03 +0530106 protected SelectionManager mSelectionManager;
Ravi Banuri7a41c372015-10-19 16:03:03 +0530107 private boolean mGetContent;
108 private boolean mShowClusterMenu;
109
Ravi Banuric963ee82015-10-20 19:41:58 +0530110 protected ActionModeHandler mActionModeHandler;
Ravi Banuri7a41c372015-10-19 16:03:03 +0530111 private int mFocusIndex = 0;
112 private DetailsHelper mDetailsHelper;
113 private MyDetailsSource mDetailsSource;
114 private MediaSet mMediaSet;
115 private boolean mShowDetails;
116 private float mUserDistance; // in pixel
117 private Future<Integer> mSyncTask = null;
118 private boolean mLaunchedFromPhotoPage;
119 private boolean mInCameraApp;
Ravi Banuric963ee82015-10-20 19:41:58 +0530120 private TextView tvEmptyAlbum;
Ravi Banuri7a41c372015-10-19 16:03:03 +0530121
122 private int mLoadingBits = 0;
123 private boolean mInitialSynced = false;
124 private int mSyncResult;
125 private boolean mLoadingFailed;
126 private RelativePosition mOpenCenter = new RelativePosition();
127
128 private Handler mHandler;
129 private static final int MSG_PICK_PHOTO = 0;
130
131 private PhotoFallbackEffect mResumeEffect;
132 private PhotoFallbackEffect.PositionProvider mPositionProvider =
133 new PhotoFallbackEffect.PositionProvider() {
Ravi Banuric963ee82015-10-20 19:41:58 +0530134 @Override
135 public Rect getPosition(int index) {
136 Rect rect = mSlotView.getSlotRect(index);
137 Rect bounds = mSlotView.bounds();
138 rect.offset(bounds.left - mSlotView.getScrollX(),
139 bounds.top - mSlotView.getScrollY());
140 return rect;
141 }
Ravi Banuri7a41c372015-10-19 16:03:03 +0530142
Ravi Banuric963ee82015-10-20 19:41:58 +0530143 @Override
144 public int getItemIndex(Path path) {
145 int start = mSlotView.getVisibleStart();
146 int end = mSlotView.getVisibleEnd();
147 for (int i = start; i < end; ++i) {
148 MediaItem item = mAlbumDataAdapter.get(i);
149 if (item != null && item.getPath() == path) return i;
150 }
151 return -1;
152 }
153 };
154
155 private Button mCameraButton;
156 private boolean mShowedEmptyToastForSelf = false;
157
Ravi Banuri7a41c372015-10-19 16:03:03 +0530158
159 @Override
160 protected int getBackgroundColorId() {
161 return R.color.album_background;
162 }
163
164 private final GLView mRootPane = new GLView() {
165 private final float mMatrix[] = new float[16];
166
167 @Override
168 protected void onLayout(
169 boolean changed, int left, int top, int right, int bottom) {
170
Chao Zhangfea8b882016-03-30 10:51:46 +0800171 int slotViewTop;
172 android.widget.Toolbar toolbar = mActivity.getToolbar();
173 if (toolbar != null) {
174 slotViewTop = toolbar.getLayoutParams().height;
175 } else {
176 slotViewTop = mActivity.getGalleryActionBar().getHeight();
177 }
Ravi Banuric963ee82015-10-20 19:41:58 +0530178 int padding =0 ;
179 if((right - left) > (bottom - top)) {
180 padding = (int) mActivity.getResources().getDimension(R.dimen.timeline_land_margin);
181 } else {
182 padding = (int) mActivity.getResources().getDimension(R.dimen.timeline_port_margin);
183 }
Ravi Banuri7a41c372015-10-19 16:03:03 +0530184 int slotViewBottom = bottom - top;
Ravi Banuric963ee82015-10-20 19:41:58 +0530185 int slotViewRight = right - left - padding;
Ravi Banuri7a41c372015-10-19 16:03:03 +0530186
187 if (mShowDetails) {
188 mDetailsHelper.layout(left, slotViewTop, right, bottom);
189 } else {
190 mAlbumView.setHighlightItemPath(null);
191 }
192
193 // Set the mSlotView as a reference point to the open animation
194 mOpenCenter.setReferencePosition(0, slotViewTop);
Ravi Banuric963ee82015-10-20 19:41:58 +0530195 mSlotView.layout(padding, slotViewTop, slotViewRight, slotViewBottom);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530196 GalleryUtils.setViewPointMatrix(mMatrix,
197 (right - left) / 2, (bottom - top) / 2, -mUserDistance);
198 }
199
200 @Override
201 protected void render(GLCanvas canvas) {
202 canvas.save(GLCanvas.SAVE_FLAG_MATRIX);
203 canvas.multiplyMatrix(mMatrix, 0);
204 super.render(canvas);
205
206 if (mResumeEffect != null) {
207 boolean more = mResumeEffect.draw(canvas);
208 if (!more) {
209 mResumeEffect = null;
210 mAlbumView.setSlotFilter(null);
211 }
212 // We want to render one more time even when no more effect
213 // required. So that the animated thumbnails could be draw
214 // with declarations in super.render().
215 invalidate();
216 }
217 canvas.restore();
218 }
219 };
220
221 // This are the transitions we want:
222 //
223 // +--------+ +------------+ +-------+ +----------+
224 // | Camera |---------->| Fullscreen |--->| Album |--->| AlbumSet |
225 // | View | thumbnail | Photo | up | Page | up | Page |
226 // +--------+ +------------+ +-------+ +----------+
227 // ^ | | ^ |
228 // | | | | | close
229 // +----------back--------+ +----back----+ +--back-> app
230 //
231 @Override
232 protected void onBackPressed() {
233 if (mShowDetails) {
234 hideDetails();
235 } else if (mSelectionManager.inSelectionMode()) {
236 mSelectionManager.leaveSelectionMode();
237 } else {
238 if(mLaunchedFromPhotoPage) {
Ravi Banuric963ee82015-10-20 19:41:58 +0530239 mActivity.getTransitionStore().putIfNotPresent(
240 PhotoPage.KEY_ALBUMPAGE_TRANSITION,
241 PhotoPage.MSG_ALBUMPAGE_RESUMED);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530242 }
Ravi Banuri7a41c372015-10-19 16:03:03 +0530243 if (mInCameraApp) {
244 super.onBackPressed();
245 } else {
246 onUpPressed();
247 }
248 }
249 }
250
251 private void onUpPressed() {
252 if (mInCameraApp) {
253 GalleryUtils.startGalleryActivity(mActivity);
Ravi Banuric963ee82015-10-20 19:41:58 +0530254 } else
Ravi Banuri7a41c372015-10-19 16:03:03 +0530255 super.onBackPressed();
Ravi Banuri7a41c372015-10-19 16:03:03 +0530256 }
257
258 private void onDown(int index) {
259 mAlbumView.setPressedIndex(index);
260 }
261
262 private void onUp(boolean followedByLongPress) {
263 if (followedByLongPress) {
264 // Avoid showing press-up animations for long-press.
265 mAlbumView.setPressedIndex(-1);
266 } else {
267 mAlbumView.setPressedUp();
268 }
269 }
270
Ravi Banuric963ee82015-10-20 19:41:58 +0530271 private void onSingleTapUp(int slotIndex , boolean isTitle) {
Ravi Banuri7a41c372015-10-19 16:03:03 +0530272 if (!mIsActive) return;
Ravi Banuric963ee82015-10-20 19:41:58 +0530273 if (mSelectionManager.inSelectionMode()) {
274 if(isTitle){
275 MediaSet targetSet = mAlbumDataAdapter.getMediaSet(slotIndex);
276 if (targetSet == null) return;
277 ArrayList<Path> paths = ((ClusterAlbum)targetSet).getMediaItems();
278 if (paths == null || paths.size() <= 0) return;
279 mSelectionManager.toggleTimeLineSet(paths);
280 mSlotView.invalidate();
281 } else {
282 MediaItem item = mAlbumDataAdapter.get(slotIndex);
283 if (item == null) return; // Item not ready yet, ignore the click
shenfed4e21e92016-11-11 15:01:14 +0800284 if (mSelectionManager.getSelectedCount() > 0) {
285 if (!ActionModeHandler.isThreadComplete)
286 return;
287 }
Ravi Banuric963ee82015-10-20 19:41:58 +0530288 mSelectionManager.toggle(item.getPath());
289 mSlotView.invalidate();
290 }
291 } else if(!isTitle){
292 // Render transition in pressed state
293 mAlbumView.setPressedIndex(slotIndex);
294 mAlbumView.setPressedUp();
295 mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_PICK_PHOTO, slotIndex, 0),
296 FadeTexture.DURATION);
297 }
Ravi Banuri7a41c372015-10-19 16:03:03 +0530298 }
299
300 private void pickPhoto(int slotIndex) {
Ravi Banuri7a41c372015-10-19 16:03:03 +0530301 pickPhoto(slotIndex, false);
302 }
303
304 private void pickPhoto(int slotIndex, boolean startInFilmstrip) {
305 if (!mIsActive) return;
306
307 if (!startInFilmstrip) {
308 // Launch photos in lights out mode
309 mActivity.getGLRoot().setLightsOutMode(true);
310 }
311
312 MediaItem item = mAlbumDataAdapter.get(slotIndex);
313
Ravi Banuri7a41c372015-10-19 16:03:03 +0530314 if (mGetContent) {
Ravi Banuric963ee82015-10-20 19:41:58 +0530315 if (item == null)
Ravi Banuri7a41c372015-10-19 16:03:03 +0530316 return; // Item not ready yet, ignore the click
Ravi Banuri7a41c372015-10-19 16:03:03 +0530317 onGetContent(item);
318 } else if (mLaunchedFromPhotoPage) {
Ravi Banuri7a41c372015-10-19 16:03:03 +0530319 TransitionStore transitions = mActivity.getTransitionStore();
320 transitions.put(
321 PhotoPage.KEY_ALBUMPAGE_TRANSITION,
322 PhotoPage.MSG_ALBUMPAGE_PICKED);
323 transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex);
324 onBackPressed();
325 } else {
Ravi Banuric963ee82015-10-20 19:41:58 +0530326 MediaSet targetset = mAlbumDataAdapter.getMediaSet(slotIndex);
327 if (targetset == null || item == null) return;
328
Ravi Banuri7a41c372015-10-19 16:03:03 +0530329 Bundle data = new Bundle();
Ravi Banuric963ee82015-10-20 19:41:58 +0530330 data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex-1);
331 data.putString(PhotoPage.KEY_MEDIA_SET_PATH,
332 targetset.getPath().toString());
Ravi Banuri7a41c372015-10-19 16:03:03 +0530333 data.putParcelable(PhotoPage.KEY_OPEN_ANIMATION_RECT,
334 mSlotView.getSlotRect(slotIndex, mRootPane));
Ravi Banuric963ee82015-10-20 19:41:58 +0530335 data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH,
336 item.getPath().toString());
337 data.putBoolean(PhotoPage.KEY_FROM_TIMELINE_SCREEN, true);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530338 data.putInt(PhotoPage.KEY_ALBUMPAGE_TRANSITION,
339 PhotoPage.MSG_ALBUMPAGE_STARTED);
340 data.putBoolean(PhotoPage.KEY_START_IN_FILMSTRIP,
341 startInFilmstrip);
Ravi Banuric963ee82015-10-20 19:41:58 +0530342 data.putBoolean(PhotoPage.KEY_IN_CAMERA_ROLL, targetset.isCameraRoll());
343 mActivity.getStateManager().startStateForResult(
344 SinglePhotoPage.class, REQUEST_PHOTO, data);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530345 }
346 }
347
348 private void onGetContent(final MediaItem item) {
349 DataManager dm = mActivity.getDataManager();
350 Activity activity = mActivity;
351 if (mData.getString(GalleryActivity.EXTRA_CROP) != null) {
352 Uri uri = dm.getContentUri(item.getPath());
353 Intent intent = new Intent(CropActivity.CROP_ACTION, uri)
354 .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT)
355 .putExtras(getData());
356 if (mData.getParcelable(MediaStore.EXTRA_OUTPUT) == null) {
357 intent.putExtra(CropExtras.KEY_RETURN_DATA, true);
358 }
359 activity.startActivity(intent);
360 activity.finish();
361 } else {
362 Intent intent = new Intent(null, item.getContentUri())
Ravi Banuric963ee82015-10-20 19:41:58 +0530363 .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530364 activity.setResult(Activity.RESULT_OK, intent);
365 activity.finish();
366 }
367 }
368
Ravi Banuric963ee82015-10-20 19:41:58 +0530369 public void onLongTap(int slotIndex, boolean isTitle) {
Ravi Banuri7a41c372015-10-19 16:03:03 +0530370 if (mGetContent) return;
Ravi Banuric963ee82015-10-20 19:41:58 +0530371 if(isTitle){
372 MediaSet targetSet = mAlbumDataAdapter.getMediaSet(slotIndex);
373 if (targetSet == null) return;
374 ArrayList<Path> paths = ((ClusterAlbum)targetSet).getMediaItems();
375 if (paths == null || paths.size() <= 0) return;
376 mSelectionManager.setAutoLeaveSelectionMode(true);
377 mSelectionManager.toggleTimeLineSet(paths);
378 mSlotView.invalidate();
379 } else {
380 MediaItem item = mAlbumDataAdapter.get(slotIndex);
381 if (item == null) return;
382 mSelectionManager.setAutoLeaveSelectionMode(true);
383 mSelectionManager.toggle(item.getPath());
384 mSlotView.invalidate();
385 }
Ravi Banuri7a41c372015-10-19 16:03:03 +0530386 }
387
388 @Override
389 public void doCluster(int clusterType) {
390 String basePath = mMediaSet.getPath().toString();
391 String newPath = FilterUtils.newClusterPath(basePath, clusterType);
392 Bundle data = new Bundle(getData());
393 data.putString(AlbumSetPage.KEY_MEDIA_PATH, newPath);
394 if (mShowClusterMenu) {
395 Context context = mActivity.getAndroidContext();
396 data.putString(AlbumSetPage.KEY_SET_TITLE, mMediaSet.getName());
397 data.putString(AlbumSetPage.KEY_SET_SUBTITLE,
398 GalleryActionBar.getClusterByTypeString(context, clusterType));
399 }
400
Ravi Banuri7a41c372015-10-19 16:03:03 +0530401 mActivity.getStateManager().startStateForResult(
402 AlbumSetPage.class, REQUEST_DO_ANIMATION, data);
403 }
404
405 @Override
406 protected void onCreate(Bundle data, Bundle restoreState) {
407 super.onCreate(data, restoreState);
408 mUserDistance = GalleryUtils.meterToPixel(USER_DISTANCE_METER);
409 initializeViews();
410 initializeData(data);
411 mGetContent = data.getBoolean(GalleryActivity.KEY_GET_CONTENT, false);
412 mShowClusterMenu = data.getBoolean(KEY_SHOW_CLUSTER_MENU, false);
413 mDetailsSource = new MyDetailsSource();
Ravi Banuri7a41c372015-10-19 16:03:03 +0530414
415 if (data.getBoolean(KEY_AUTO_SELECT_ALL)) {
416 mSelectionManager.selectAll();
417 }
418
419 mLaunchedFromPhotoPage =
420 mActivity.getStateManager().hasStateClass(FilmstripPage.class);
421 mInCameraApp = data.getBoolean(PhotoPage.KEY_APP_BRIDGE, false);
422
423 mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
424 @Override
425 public void handleMessage(Message message) {
426 switch (message.what) {
427 case MSG_PICK_PHOTO: {
428 pickPhoto(message.arg1);
429 break;
430 }
431 default:
432 throw new AssertionError(message.what);
433 }
434 }
435 };
436 }
437
438 @Override
439 protected void onResume() {
440 super.onResume();
Ravi Banuric963ee82015-10-20 19:41:58 +0530441
Ravi Banuri7a41c372015-10-19 16:03:03 +0530442 mIsActive = true;
443
444 mResumeEffect = mActivity.getTransitionStore().get(KEY_RESUME_ANIMATION);
445 if (mResumeEffect != null) {
446 mAlbumView.setSlotFilter(mResumeEffect);
447 mResumeEffect.setPositionProvider(mPositionProvider);
448 mResumeEffect.start();
449 }
450
451 setContentPane(mRootPane);
452
Ravi Banuri7a41c372015-10-19 16:03:03 +0530453 // Set the reload bit here to prevent it exit this page in clearLoadingBit().
454 setLoadingBit(BIT_LOADING_RELOAD);
huiyane9fa3d62016-04-13 12:48:07 +0800455 if (null != mMediaSet) {
456 //set to show timeline title
Kedi Xufece30c2016-10-21 15:13:32 +0800457 mMediaSet.setShowAlbumsetTimeTitle(true);
huiyane9fa3d62016-04-13 12:48:07 +0800458 }
Ravi Banuri7a41c372015-10-19 16:03:03 +0530459 mLoadingFailed = false;
460 mAlbumDataAdapter.resume();
461
462 mAlbumView.resume();
463 mAlbumView.setPressedIndex(-1);
464 mActionModeHandler.resume();
465 if (!mInitialSynced) {
466 setLoadingBit(BIT_LOADING_SYNC);
467 mSyncTask = mMediaSet.requestSync(this);
468 }
Ravi Banuri7a41c372015-10-19 16:03:03 +0530469 }
470
471 @Override
472 protected void onPause() {
473 super.onPause();
474 mIsActive = false;
475
Ravi Banuri7a41c372015-10-19 16:03:03 +0530476 mAlbumView.setSlotFilter(null);
477 mActionModeHandler.pause();
478 mAlbumDataAdapter.pause();
479 mAlbumView.pause();
480 DetailsHelper.pause();
Ravi Banuric963ee82015-10-20 19:41:58 +0530481 /*if (!mGetContent) {
Ravi Banuri7a41c372015-10-19 16:03:03 +0530482 mActivity.getGalleryActionBar().disableAlbumModeMenu(true);
Ravi Banuric963ee82015-10-20 19:41:58 +0530483 }*/
Ravi Banuri7a41c372015-10-19 16:03:03 +0530484
485 if (mSyncTask != null) {
486 mSyncTask.cancel();
487 mSyncTask = null;
488 clearLoadingBit(BIT_LOADING_SYNC);
489 }
Ravi Banuric963ee82015-10-20 19:41:58 +0530490
491 hideEmptyAlbumToast();
492 hideCameraButton();
Ravi Banuri7a41c372015-10-19 16:03:03 +0530493 }
494
495 @Override
496 protected void onDestroy() {
497 super.onDestroy();
498 if (mAlbumDataAdapter != null) {
499 mAlbumDataAdapter.setLoadingListener(null);
500 }
501 mActionModeHandler.destroy();
502 }
503
504 private void initializeViews() {
505 mSelectionManager = new SelectionManager(mActivity, false);
506 mSelectionManager.setSelectionListener(this);
Ravi Banuric963ee82015-10-20 19:41:58 +0530507 Config.TimeLinePage config = Config.TimeLinePage.get(mActivity);
508 mSlotView = new TimeLineSlotView(mActivity, config.slotViewSpec);
509 mAlbumView = new TimeLineSlotRenderer(mActivity, mSlotView,
510 mSelectionManager, config.labelSpec, config.placeholderColor);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530511 mSlotView.setSlotRenderer(mAlbumView);
512 mRootPane.addComponent(mSlotView);
Ravi Banuric963ee82015-10-20 19:41:58 +0530513 mSlotView.setListener(new TimeLineSlotView.SimpleListener() {
Ravi Banuri7a41c372015-10-19 16:03:03 +0530514 @Override
515 public void onDown(int index) {
Ravi Banuric963ee82015-10-20 19:41:58 +0530516 TimeLinePage.this.onDown(index);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530517 }
518
519 @Override
520 public void onUp(boolean followedByLongPress) {
Ravi Banuric963ee82015-10-20 19:41:58 +0530521 TimeLinePage.this.onUp(followedByLongPress);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530522 }
523
524 @Override
Ravi Banuric963ee82015-10-20 19:41:58 +0530525 public void onSingleTapUp(int slotIndex, boolean isTitle) {
526 TimeLinePage.this.onSingleTapUp(slotIndex, isTitle);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530527 }
528
529 @Override
Ravi Banuric963ee82015-10-20 19:41:58 +0530530 public void onLongTap(int slotIndex, boolean isTitle) {
531 TimeLinePage.this.onLongTap(slotIndex, isTitle);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530532 }
533 });
534 mActionModeHandler = new ActionModeHandler(mActivity, mSelectionManager);
535 mActionModeHandler.setActionModeListener(new ActionModeListener() {
536 @Override
537 public boolean onActionItemClicked(MenuItem item) {
538 return onItemSelected(item);
539 }
540 });
541 }
542
543 private void initializeData(Bundle data) {
544 mMediaSetPath = Path.fromString(data.getString(KEY_MEDIA_PATH));
Ravi Banuri7a41c372015-10-19 16:03:03 +0530545 mMediaSet = mActivity.getDataManager().getMediaSet(mMediaSetPath);
546 if (mMediaSet == null) {
547 Utils.fail("MediaSet is null. Path = %s", mMediaSetPath);
548 }
Ravi Banuric963ee82015-10-20 19:41:58 +0530549 mAlbumDataAdapter = new TimeLineDataLoader(mActivity, mMediaSet);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530550 mSelectionManager.setSourceMediaSet(mMediaSet);
Kedi Xude4bbef2016-08-04 18:21:04 +0800551 mSelectionManager.setTimeLineDataLoader(mAlbumDataAdapter);
Ravi Banuric963ee82015-10-20 19:41:58 +0530552 //mSelectionManager.setAlbumDataAdapter(mAlbumDataAdapter);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530553 mAlbumDataAdapter.setLoadingListener(new MyLoadingListener());
554 mAlbumView.setModel(mAlbumDataAdapter);
555 }
556
557 private void showDetails() {
558 mShowDetails = true;
559 if (mDetailsHelper == null) {
560 mDetailsHelper = new DetailsHelper(mActivity, mRootPane, mDetailsSource);
561 mDetailsHelper.setCloseListener(new CloseListener() {
562 @Override
563 public void onClose() {
564 hideDetails();
565 }
566 });
567 }
568 mDetailsHelper.show();
569 }
570
571 private void hideDetails() {
572 mShowDetails = false;
573 mDetailsHelper.hide();
574 mAlbumView.setHighlightItemPath(null);
575 mSlotView.invalidate();
576 }
577
578 @Override
579 protected boolean onCreateActionBar(Menu menu) {
580 GalleryActionBar actionBar = mActivity.getGalleryActionBar();
581 MenuInflater inflator = getSupportMenuInflater();
582 if (mGetContent) {
583 inflator.inflate(R.menu.pickup, menu);
584 int typeBits = mData.getInt(GalleryActivity.KEY_TYPE_BITS,
585 DataManager.INCLUDE_IMAGE);
586 actionBar.setTitle(GalleryUtils.getSelectionModePrompt(typeBits));
587 } else {
588 inflator.inflate(R.menu.album, menu);
Ravi Banuric963ee82015-10-20 19:41:58 +0530589 actionBar.setTitle(R.string.timeline_title);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530590
591 FilterUtils.setupMenuItems(actionBar, mMediaSetPath, true);
Ravi Banuric963ee82015-10-20 19:41:58 +0530592 //menu.findItem(R.id.action_group_by).setVisible(mShowClusterMenu);
593 menu.findItem(R.id.action_camera).setVisible(GalleryUtils.isAnyCameraAvailable(mActivity));
Ravi Banuric963ee82015-10-20 19:41:58 +0530594 menu.findItem(R.id.action_view_type).setVisible(false);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530595 }
Ravi Banuric963ee82015-10-20 19:41:58 +0530596
Ravi Banuri7a41c372015-10-19 16:03:03 +0530597 return true;
598 }
599
600 private void prepareAnimationBackToFilmstrip(int slotIndex) {
601 if (mAlbumDataAdapter == null || !mAlbumDataAdapter.isActive(slotIndex)) return;
602 MediaItem item = mAlbumDataAdapter.get(slotIndex);
603 if (item == null) return;
604 TransitionStore transitions = mActivity.getTransitionStore();
605 transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex);
606 transitions.put(PhotoPage.KEY_OPEN_ANIMATION_RECT,
607 mSlotView.getSlotRect(slotIndex, mRootPane));
608 }
609
610 private void switchToFilmstrip() {
611 // Invalid album, return back directly.
612 if (mAlbumDataAdapter.size() < 1) {
613 return;
614 }
615
616 int targetPhoto = mSlotView.getVisibleStart();
617 if (View.LAYOUT_DIRECTION_RTL == TextUtils
618 .getLayoutDirectionFromLocale(Locale.getDefault())) {
619 // Fetch corresponding index from another side, only in RTL
620 targetPhoto = mAlbumDataAdapter.size() - targetPhoto - 1;
621 }
622 prepareAnimationBackToFilmstrip(targetPhoto);
623 if(mLaunchedFromPhotoPage) {
624 onBackPressed();
625 } else {
626 pickPhoto(targetPhoto, true);
627 }
628 }
629
630 @Override
631 protected boolean onItemSelected(MenuItem item) {
632 switch (item.getItemId()) {
633 case android.R.id.home: {
634 onUpPressed();
635 return true;
636 }
637 case R.id.action_cancel:
638 mActivity.getStateManager().finishState(this);
639 return true;
640 case R.id.action_select:
Ravi Banuric963ee82015-10-20 19:41:58 +0530641 mSelectionManager.setAutoLeaveSelectionMode(true);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530642 mSelectionManager.enterSelectionMode();
643 return true;
Ravi Banuri7a41c372015-10-19 16:03:03 +0530644 case R.id.action_slideshow: {
Ravi Banuri7a41c372015-10-19 16:03:03 +0530645 Bundle data = new Bundle();
646 data.putString(SlideshowPage.KEY_SET_PATH,
647 mMediaSetPath.toString());
648 data.putBoolean(SlideshowPage.KEY_REPEAT, true);
649 mActivity.getStateManager().startStateForResult(
650 SlideshowPage.class, REQUEST_SLIDESHOW, data);
651 return true;
652 }
653 case R.id.action_details: {
654 if (mShowDetails) {
655 hideDetails();
656 } else {
657 showDetails();
658 }
659 return true;
660 }
661 case R.id.action_camera: {
662 GalleryUtils.startCameraActivity(mActivity);
663 return true;
664 }
665 default:
666 return false;
667 }
668 }
669
670 @Override
671 protected void onStateResult(int request, int result, Intent data) {
672 switch (request) {
Ravi Banuric963ee82015-10-20 19:41:58 +0530673 case REQUEST_SLIDESHOW:
674 {
Ravi Banuri7a41c372015-10-19 16:03:03 +0530675 // data could be null, if there is no images in the album
676 if (data == null) return;
677 mFocusIndex = data.getIntExtra(SlideshowPage.KEY_PHOTO_INDEX, 0);
678 mSlotView.setCenterIndex(mFocusIndex);
679 break;
680 }
681 case REQUEST_PHOTO: {
682 if (data == null) return;
683 mFocusIndex = data.getIntExtra(PhotoPage.KEY_RETURN_INDEX_HINT, 0);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530684 mSlotView.makeSlotVisible(mFocusIndex);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530685 break;
686 }
687 case REQUEST_DO_ANIMATION: {
688 mSlotView.startRisingAnimation();
689 break;
690 }
691 }
692 }
693
694 @Override
695 public void onSelectionModeChange(int mode) {
696 switch (mode) {
697 case SelectionManager.ENTER_SELECTION_MODE: {
698 mActionModeHandler.startActionMode();
699 performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
Arne Coucheronccbf7a72017-07-13 01:36:11 +0200700 ((GalleryActivity) mActivity).toggleNavBar(false);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530701 break;
702 }
703 case SelectionManager.LEAVE_SELECTION_MODE: {
704 mActionModeHandler.finishActionMode();
Arne Coucheronccbf7a72017-07-13 01:36:11 +0200705 ((GalleryActivity) mActivity).toggleNavBar(true);
Ravi Banuri7a41c372015-10-19 16:03:03 +0530706 mRootPane.invalidate();
707 break;
708 }
Abhishek Panjikar9775cc32015-11-06 17:30:50 +0530709 case SelectionManager.SELECT_ALL_MODE: {
Ravi Banuri7a41c372015-10-19 16:03:03 +0530710 mActionModeHandler.updateSupportedOperation();
711 mRootPane.invalidate();
712 break;
713 }
714 }
715 }
716
717 @Override
718 public void onSelectionChange(Path path, boolean selected) {
719 int count = mSelectionManager.getSelectedCount();
720 String format = mActivity.getResources().getQuantityString(
721 R.plurals.number_of_items_selected, count);
722 mActionModeHandler.setTitle(String.format(format, count));
723 mActionModeHandler.updateSupportedOperation(path, selected);
724 }
725
726 @Override
727 public void onSyncDone(final MediaSet mediaSet, final int resultCode) {
728 Log.d(TAG, "onSyncDone: " + Utils.maskDebugInfo(mediaSet.getName()) + " result="
729 + resultCode);
Ravi Banuric963ee82015-10-20 19:41:58 +0530730 mActivity.runOnUiThread(new Runnable() {
Ravi Banuri7a41c372015-10-19 16:03:03 +0530731 @Override
732 public void run() {
733 GLRoot root = mActivity.getGLRoot();
734 root.lockRenderThread();
735 mSyncResult = resultCode;
736 try {
737 if (resultCode == MediaSet.SYNC_RESULT_SUCCESS) {
738 mInitialSynced = true;
739 }
740 clearLoadingBit(BIT_LOADING_SYNC);
741 showSyncErrorIfNecessary(mLoadingFailed);
742 } finally {
743 root.unlockRenderThread();
744 }
745 }
746 });
747 }
748
749 // Show sync error toast when all the following conditions are met:
750 // (1) both loading and sync are done,
751 // (2) sync result is error,
752 // (3) the page is still active, and
753 // (4) no photo is shown or loading fails.
754 private void showSyncErrorIfNecessary(boolean loadingFailed) {
755 if ((mLoadingBits == 0) && (mSyncResult == MediaSet.SYNC_RESULT_ERROR) && mIsActive
756 && (loadingFailed || (mAlbumDataAdapter.size() == 0))) {
757 Toast.makeText(mActivity, R.string.sync_album_error,
758 Toast.LENGTH_LONG).show();
759 }
760 }
761
762 private void setLoadingBit(int loadTaskBit) {
763 mLoadingBits |= loadTaskBit;
764 }
765
766 private void clearLoadingBit(int loadTaskBit) {
767 mLoadingBits &= ~loadTaskBit;
768 if (mLoadingBits == 0 && mIsActive) {
769 if (mAlbumDataAdapter.size() == 0) {
Ravi Banuric963ee82015-10-20 19:41:58 +0530770 mShowedEmptyToastForSelf = true;
771 showEmptyAlbumToast(Toast.LENGTH_LONG);
772 mSlotView.invalidate();
yonggab7e00552016-01-11 18:39:11 +0800773 } else {
774 hideEmptyAlbumToast();
Ravi Banuri7a41c372015-10-19 16:03:03 +0530775 }
Ravi Banuric963ee82015-10-20 19:41:58 +0530776 return;
777 }
778 // Hide the empty album toast if we are in the root instance of
779 // AlbumSetPage and the album is no longer empty (for instance,
780 // after a sync is completed and web albums have been synced)
781 if (mShowedEmptyToastForSelf) {
782 mShowedEmptyToastForSelf = false;
783 hideEmptyAlbumToast();
784 //hideCameraButton();
Ravi Banuri7a41c372015-10-19 16:03:03 +0530785 }
786 }
787
788 private class MyLoadingListener implements LoadingListener {
789 @Override
790 public void onLoadingStarted() {
791 setLoadingBit(BIT_LOADING_RELOAD);
792 mLoadingFailed = false;
793 }
794
795 @Override
796 public void onLoadingFinished(boolean loadingFailed) {
797 clearLoadingBit(BIT_LOADING_RELOAD);
798 mLoadingFailed = loadingFailed;
799 showSyncErrorIfNecessary(loadingFailed);
800 }
801 }
802
803 private class MyDetailsSource implements DetailsHelper.DetailsSource {
804 private int mIndex;
805
806 @Override
807 public int size() {
Ravi Banuric963ee82015-10-20 19:41:58 +0530808 return mAlbumDataAdapter.size() - mAlbumDataAdapter.getTimeLineTitlesCount();
Ravi Banuri7a41c372015-10-19 16:03:03 +0530809 }
810
811 @Override
812 public int setIndex() {
Ravi Banuric963ee82015-10-20 19:41:58 +0530813 if (mSelectionManager.getSelected(false) == null) return -1;
Ravi Banuri7a41c372015-10-19 16:03:03 +0530814 Path id = mSelectionManager.getSelected(false).get(0);
815 mIndex = mAlbumDataAdapter.findItem(id);
Chao Zhang78e8aba2016-04-21 20:08:14 +0800816 int indexToDisplay = mAlbumDataAdapter.getIndex(id, false);
817 return indexToDisplay;
Ravi Banuri7a41c372015-10-19 16:03:03 +0530818 }
819
820 @Override
821 public MediaDetails getDetails() {
822 // this relies on setIndex() being called beforehand
Ravi Banuric963ee82015-10-20 19:41:58 +0530823 if (mIndex < 0) return null;
Ravi Banuri7a41c372015-10-19 16:03:03 +0530824 MediaObject item = mAlbumDataAdapter.get(mIndex);
825 if (item != null) {
826 mAlbumView.setHighlightItemPath(item.getPath());
827 return item.getDetails();
828 } else {
829 return null;
830 }
831 }
832 }
833
834 @Override
835 public void onAlbumModeSelected(int mode) {
836 if (mode == GalleryActionBar.ALBUM_FILMSTRIP_MODE_SELECTED) {
837 switchToFilmstrip();
838 }
839 }
Ravi Banuric963ee82015-10-20 19:41:58 +0530840
841 private WeakReference<Toast> mEmptyAlbumToast = null;
842
843 private void showCameraButton() {
844 if (mCameraButton == null && !setupCameraButton()) return;
845 mCameraButton.setVisibility(View.VISIBLE);
846 }
847
848 private void hideCameraButton() {
849 if (mCameraButton == null) return;
850 mCameraButton.setVisibility(View.GONE);
851 }
852
853 private boolean setupCameraButton() {
854 if (!GalleryUtils.isAnyCameraAvailable(mActivity)) return false;
855 RelativeLayout galleryRoot = (RelativeLayout)mActivity.findViewById(R.id.gallery_root);
856 if (galleryRoot == null) return false;
857
858 mCameraButton = new Button(mActivity);
859 mCameraButton.setText(R.string.camera_label);
860 mCameraButton.setCompoundDrawablesWithIntrinsicBounds(0, R.drawable.frame_overlay_gallery_camera, 0, 0);
861 mCameraButton.setOnClickListener(new OnClickListener() {
862 @Override
863 public void onClick(View arg0) {
864 GalleryUtils.startCameraActivity(mActivity);
865 }
866 });
867 RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
868 RelativeLayout.LayoutParams.WRAP_CONTENT,
869 RelativeLayout.LayoutParams.WRAP_CONTENT);
870 lp.addRule(RelativeLayout.CENTER_IN_PARENT);
871 galleryRoot.addView(mCameraButton, lp);
872 return true;
873 }
874
875 private void showEmptyAlbumToast(int toastLength) {
yonggab7e00552016-01-11 18:39:11 +0800876 RelativeLayout galleryRoot = (RelativeLayout) mActivity.findViewById(R.id.gallery_root);
877 if (galleryRoot == null) return;
878 if (tvEmptyAlbum == null) {
879 tvEmptyAlbum = new TextView(mActivity);
880 tvEmptyAlbum.setText(R.string.tvEmptyAlbum);
881 tvEmptyAlbum.setTextColor(Color.parseColor("#8A000000"));
882 tvEmptyAlbum.setGravity(Gravity.CENTER);
883 tvEmptyAlbum.setTextSize(TypedValue.COMPLEX_UNIT_SP, 20);
884 RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(
885 RelativeLayout.LayoutParams.WRAP_CONTENT,
886 RelativeLayout.LayoutParams.WRAP_CONTENT);
887 lp.addRule(RelativeLayout.CENTER_IN_PARENT);
888 galleryRoot.addView(tvEmptyAlbum, lp);
889 }
890 tvEmptyAlbum.setVisibility(View.VISIBLE);
Ravi Banuric963ee82015-10-20 19:41:58 +0530891 }
892
893 private void hideEmptyAlbumToast() {
yonggab7e00552016-01-11 18:39:11 +0800894 if (tvEmptyAlbum != null) {
895 tvEmptyAlbum.setVisibility(View.GONE);
896 }
Ravi Banuric963ee82015-10-20 19:41:58 +0530897 }
Ravi Banuri7a41c372015-10-19 16:03:03 +0530898}