blob: 29df6068774ddc49998639ca1f24f9ad242b70f2 [file] [log] [blame]
Owen Linf9a0a432011-08-17 22:07:43 +08001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.gallery3d.app;
18
Paramanandac12b8b12015-03-24 17:51:29 +053019import java.util.ArrayList;
20import java.util.Random;
21
Owen Linf9a0a432011-08-17 22:07:43 +080022import android.app.Activity;
Owen Linf9a0a432011-08-17 22:07:43 +080023import android.content.Intent;
Anand Chaudhari922a2fa2015-09-23 18:01:06 +053024//import android.drm.DrmHelper;
Owen Linf9a0a432011-08-17 22:07:43 +080025import android.graphics.Bitmap;
26import android.os.Bundle;
27import android.os.Handler;
28import android.os.Message;
Owen Linf9a0a432011-08-17 22:07:43 +080029import android.view.MotionEvent;
30
Likai Dingc83b5b72016-05-25 14:48:41 +080031import org.codeaurora.gallery.R;
Ray Chen604f0532011-10-21 16:07:12 +080032import com.android.gallery3d.common.Utils;
33import com.android.gallery3d.data.ContentListener;
34import com.android.gallery3d.data.MediaItem;
35import com.android.gallery3d.data.MediaObject;
36import com.android.gallery3d.data.MediaSet;
37import com.android.gallery3d.data.Path;
John Recka4eae1a2012-12-11 14:42:27 -080038import com.android.gallery3d.glrenderer.GLCanvas;
Ray Chen604f0532011-10-21 16:07:12 +080039import com.android.gallery3d.ui.GLView;
40import com.android.gallery3d.ui.SlideshowView;
41import com.android.gallery3d.ui.SynchronizedHandler;
42import com.android.gallery3d.util.Future;
43import com.android.gallery3d.util.FutureListener;
44
Owen Linf9a0a432011-08-17 22:07:43 +080045public class SlideshowPage extends ActivityState {
46 private static final String TAG = "SlideshowPage";
47
48 public static final String KEY_SET_PATH = "media-set-path";
49 public static final String KEY_ITEM_PATH = "media-item-path";
50 public static final String KEY_PHOTO_INDEX = "photo-index";
51 public static final String KEY_RANDOM_ORDER = "random-order";
52 public static final String KEY_REPEAT = "repeat";
Yuli Huangafb3d1d2012-05-28 23:39:27 +080053 public static final String KEY_DREAM = "dream";
Owen Linf9a0a432011-08-17 22:07:43 +080054
55 private static final long SLIDESHOW_DELAY = 3000; // 3 seconds
56
57 private static final int MSG_LOAD_NEXT_BITMAP = 1;
58 private static final int MSG_SHOW_PENDING_BITMAP = 2;
59
60 public static interface Model {
61 public void pause();
Ray Chen604f0532011-10-21 16:07:12 +080062
Owen Linf9a0a432011-08-17 22:07:43 +080063 public void resume();
Ray Chen604f0532011-10-21 16:07:12 +080064
Owen Linf9a0a432011-08-17 22:07:43 +080065 public Future<Slide> nextSlide(FutureListener<Slide> listener);
66 }
67
68 public static class Slide {
69 public Bitmap bitmap;
70 public MediaItem item;
71 public int index;
72
73 public Slide(MediaItem item, int index, Bitmap bitmap) {
74 this.bitmap = bitmap;
75 this.item = item;
76 this.index = index;
77 }
78 }
79
80 private Handler mHandler;
81 private Model mModel;
82 private SlideshowView mSlideshowView;
83
84 private Slide mPendingSlide = null;
85 private boolean mIsActive = false;
Ray Chen604f0532011-10-21 16:07:12 +080086 private final Intent mResultIntent = new Intent();
Owen Linf9a0a432011-08-17 22:07:43 +080087
Bobby Georgescu915c2c52012-08-23 13:05:53 -070088 @Override
89 protected int getBackgroundColorId() {
90 return R.color.slideshow_background;
91 }
92
Ray Chen604f0532011-10-21 16:07:12 +080093 private final GLView mRootPane = new GLView() {
Owen Linf9a0a432011-08-17 22:07:43 +080094 @Override
Ray Chen604f0532011-10-21 16:07:12 +080095 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
Owen Linf9a0a432011-08-17 22:07:43 +080096 mSlideshowView.layout(0, 0, right - left, bottom - top);
97 }
98
99 @Override
100 protected boolean onTouch(MotionEvent event) {
101 if (event.getAction() == MotionEvent.ACTION_UP) {
102 onBackPressed();
103 }
104 return true;
105 }
106
107 @Override
108 protected void renderBackground(GLCanvas canvas) {
Bobby Georgescu915c2c52012-08-23 13:05:53 -0700109 canvas.clearBuffer(getBackgroundColor());
Owen Linf9a0a432011-08-17 22:07:43 +0800110 }
111 };
112
113 @Override
114 public void onCreate(Bundle data, Bundle restoreState) {
Bobby Georgescu45c56f22012-08-26 23:47:19 -0700115 super.onCreate(data, restoreState);
Joey Rizzoli0a421722016-06-01 14:04:38 +0200116 ((GalleryActivity) mActivity).toggleNavBar(false);
117
huiyan8782c242016-04-23 14:52:23 +0800118 mFlags |= (FLAG_HIDE_ACTION_BAR | FLAG_HIDE_STATUS_BAR | FLAG_SCREEN_FULL);
Yuli Huangafb3d1d2012-05-28 23:39:27 +0800119 if (data.getBoolean(KEY_DREAM)) {
120 // Dream screensaver only keeps screen on for plugged devices.
Doris Liu4a10c972013-04-16 15:54:42 -0700121 mFlags |= FLAG_SCREEN_ON_WHEN_PLUGGED | FLAG_SHOW_WHEN_LOCKED;
Yuli Huangafb3d1d2012-05-28 23:39:27 +0800122 } else {
123 // User-initiated slideshow would always keep screen on.
124 mFlags |= FLAG_SCREEN_ON_ALWAYS;
125 }
Owen Linf9a0a432011-08-17 22:07:43 +0800126
127 mHandler = new SynchronizedHandler(mActivity.getGLRoot()) {
128 @Override
129 public void handleMessage(Message message) {
130 switch (message.what) {
131 case MSG_SHOW_PENDING_BITMAP:
132 showPendingBitmap();
133 break;
134 case MSG_LOAD_NEXT_BITMAP:
135 loadNextBitmap();
136 break;
137 default: throw new AssertionError();
138 }
139 }
140 };
141 initializeViews();
142 initializeData(data);
zhuwc4d3c762017-07-12 14:11:52 +0800143 Log.d(GalleryActivity.QSST, "enter slide show successfully");
Owen Linf9a0a432011-08-17 22:07:43 +0800144 }
145
146 private void loadNextBitmap() {
147 mModel.nextSlide(new FutureListener<Slide>() {
Ahbong Chang78179792012-07-30 11:34:13 +0800148 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800149 public void onFutureDone(Future<Slide> future) {
150 mPendingSlide = future.get();
151 mHandler.sendEmptyMessage(MSG_SHOW_PENDING_BITMAP);
152 }
153 });
154 }
155
156 private void showPendingBitmap() {
157 // mPendingBitmap could be null, if
Ray Chen604f0532011-10-21 16:07:12 +0800158 // 1.) there is no more items
159 // 2.) mModel is paused
Owen Linf9a0a432011-08-17 22:07:43 +0800160 Slide slide = mPendingSlide;
161 if (slide == null) {
162 if (mIsActive) {
163 mActivity.getStateManager().finishState(SlideshowPage.this);
164 }
165 return;
166 }
167
168 mSlideshowView.next(slide.bitmap, slide.item.getRotation());
169
170 setStateResult(Activity.RESULT_OK, mResultIntent
171 .putExtra(KEY_ITEM_PATH, slide.item.getPath().toString())
172 .putExtra(KEY_PHOTO_INDEX, slide.index));
Ray Chen604f0532011-10-21 16:07:12 +0800173 mHandler.sendEmptyMessageDelayed(MSG_LOAD_NEXT_BITMAP, SLIDESHOW_DELAY);
Owen Linf9a0a432011-08-17 22:07:43 +0800174 }
175
176 @Override
177 public void onPause() {
178 super.onPause();
Arne Coucheronccbf7a72017-07-13 01:36:11 +0200179 if (mActivity.getStateManager().getStateCount() <= 1) {
180 ((GalleryActivity) mActivity).toggleNavBar(true);
181 }
Owen Linf9a0a432011-08-17 22:07:43 +0800182 mIsActive = false;
183 mModel.pause();
184 mSlideshowView.release();
185
186 mHandler.removeMessages(MSG_LOAD_NEXT_BITMAP);
187 mHandler.removeMessages(MSG_SHOW_PENDING_BITMAP);
188 }
189
190 @Override
191 public void onResume() {
192 super.onResume();
Joey Rizzoli0a421722016-06-01 14:04:38 +0200193 ((GalleryActivity) mActivity).toggleNavBar(false);
Owen Linf9a0a432011-08-17 22:07:43 +0800194 mIsActive = true;
195 mModel.resume();
196
197 if (mPendingSlide != null) {
198 showPendingBitmap();
199 } else {
200 loadNextBitmap();
201 }
202 }
203
204 private void initializeData(Bundle data) {
Owen Linf9a0a432011-08-17 22:07:43 +0800205 boolean random = data.getBoolean(KEY_RANDOM_ORDER, false);
Chih-Chung Chang78979fc2011-09-09 16:41:54 +0800206
207 // We only want to show slideshow for images only, not videos.
208 String mediaPath = data.getString(KEY_SET_PATH);
Ray Chen604f0532011-10-21 16:07:12 +0800209 mediaPath = FilterUtils.newFilterPath(mediaPath, FilterUtils.FILTER_IMAGE_ONLY);
Owen Linf9a0a432011-08-17 22:07:43 +0800210 MediaSet mediaSet = mActivity.getDataManager().getMediaSet(mediaPath);
211
212 if (random) {
213 boolean repeat = data.getBoolean(KEY_REPEAT);
Ray Chen604f0532011-10-21 16:07:12 +0800214 mModel = new SlideshowDataAdapter(mActivity,
215 new ShuffleSource(mediaSet, repeat), 0, null);
216 setStateResult(Activity.RESULT_OK, mResultIntent.putExtra(KEY_PHOTO_INDEX, 0));
Owen Linf9a0a432011-08-17 22:07:43 +0800217 } else {
218 int index = data.getInt(KEY_PHOTO_INDEX);
Ray Chen50620062011-11-03 15:47:38 +0800219 String itemPath = data.getString(KEY_ITEM_PATH);
220 Path path = itemPath != null ? Path.fromString(itemPath) : null;
Owen Linf9a0a432011-08-17 22:07:43 +0800221 boolean repeat = data.getBoolean(KEY_REPEAT);
Ray Chen604f0532011-10-21 16:07:12 +0800222 mModel = new SlideshowDataAdapter(mActivity, new SequentialSource(mediaSet, repeat),
223 index, path);
224 setStateResult(Activity.RESULT_OK, mResultIntent.putExtra(KEY_PHOTO_INDEX, index));
Owen Linf9a0a432011-08-17 22:07:43 +0800225 }
226 }
227
228 private void initializeViews() {
229 mSlideshowView = new SlideshowView();
230 mRootPane.addComponent(mSlideshowView);
231 setContentPane(mRootPane);
232 }
233
234 private static MediaItem findMediaItem(MediaSet mediaSet, int index) {
235 for (int i = 0, n = mediaSet.getSubMediaSetCount(); i < n; ++i) {
236 MediaSet subset = mediaSet.getSubMediaSet(i);
237 int count = subset.getTotalMediaItemCount();
238 if (index < count) {
239 return findMediaItem(subset, index);
240 }
241 index -= count;
242 }
243 ArrayList<MediaItem> list = mediaSet.getMediaItem(index, 1);
244 return list.isEmpty() ? null : list.get(0);
245 }
246
247 private static class ShuffleSource implements SlideshowDataAdapter.SlideshowSource {
248 private static final int RETRY_COUNT = 5;
249 private final MediaSet mMediaSet;
250 private final Random mRandom = new Random();
251 private int mOrder[] = new int[0];
Ray Chen604f0532011-10-21 16:07:12 +0800252 private final boolean mRepeat;
Owen Linf9a0a432011-08-17 22:07:43 +0800253 private long mSourceVersion = MediaSet.INVALID_DATA_VERSION;
254 private int mLastIndex = -1;
255
256 public ShuffleSource(MediaSet mediaSet, boolean repeat) {
257 mMediaSet = Utils.checkNotNull(mediaSet);
258 mRepeat = repeat;
259 }
260
Ahbong Chang78179792012-07-30 11:34:13 +0800261 @Override
Ray Chen604f0532011-10-21 16:07:12 +0800262 public int findItemIndex(Path path, int hint) {
263 return hint;
264 }
265
Ahbong Chang78179792012-07-30 11:34:13 +0800266 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800267 public MediaItem getMediaItem(int index) {
268 if (!mRepeat && index >= mOrder.length) return null;
Chih-Chung Chang78979fc2011-09-09 16:41:54 +0800269 if (mOrder.length == 0) return null;
Owen Linf9a0a432011-08-17 22:07:43 +0800270 mLastIndex = mOrder[index % mOrder.length];
271 MediaItem item = findMediaItem(mMediaSet, mLastIndex);
272 for (int i = 0; i < RETRY_COUNT && item == null; ++i) {
273 Log.w(TAG, "fail to find image: " + mLastIndex);
274 mLastIndex = mRandom.nextInt(mOrder.length);
275 item = findMediaItem(mMediaSet, mLastIndex);
276 }
277 return item;
278 }
279
Ahbong Chang78179792012-07-30 11:34:13 +0800280 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800281 public long reload() {
John Reck705dc812013-03-21 14:22:33 -0700282 long version = mMediaSet.reload();
Owen Linf9a0a432011-08-17 22:07:43 +0800283 if (version != mSourceVersion) {
284 mSourceVersion = version;
285 int count = mMediaSet.getTotalMediaItemCount();
286 if (count != mOrder.length) generateOrderArray(count);
287 }
288 return version;
289 }
290
291 private void generateOrderArray(int totalCount) {
292 if (mOrder.length != totalCount) {
293 mOrder = new int[totalCount];
294 for (int i = 0; i < totalCount; ++i) {
295 mOrder[i] = i;
296 }
297 }
298 for (int i = totalCount - 1; i > 0; --i) {
299 Utils.swap(mOrder, i, mRandom.nextInt(i + 1));
300 }
301 if (mOrder[0] == mLastIndex && totalCount > 1) {
302 Utils.swap(mOrder, 0, mRandom.nextInt(totalCount - 1) + 1);
303 }
304 }
305
Ahbong Chang78179792012-07-30 11:34:13 +0800306 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800307 public void addContentListener(ContentListener listener) {
308 mMediaSet.addContentListener(listener);
309 }
310
Ahbong Chang78179792012-07-30 11:34:13 +0800311 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800312 public void removeContentListener(ContentListener listener) {
313 mMediaSet.removeContentListener(listener);
314 }
315 }
316
317 private static class SequentialSource implements SlideshowDataAdapter.SlideshowSource {
318 private static final int DATA_SIZE = 32;
319
320 private ArrayList<MediaItem> mData = new ArrayList<MediaItem>();
321 private int mDataStart = 0;
322 private long mDataVersion = MediaObject.INVALID_DATA_VERSION;
323 private final MediaSet mMediaSet;
324 private final boolean mRepeat;
325
326 public SequentialSource(MediaSet mediaSet, boolean repeat) {
327 mMediaSet = mediaSet;
328 mRepeat = repeat;
329 }
330
Ahbong Chang78179792012-07-30 11:34:13 +0800331 @Override
Ray Chen604f0532011-10-21 16:07:12 +0800332 public int findItemIndex(Path path, int hint) {
333 return mMediaSet.getIndexOfItem(path, hint);
334 }
335
Ahbong Chang78179792012-07-30 11:34:13 +0800336 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800337 public MediaItem getMediaItem(int index) {
338 int dataEnd = mDataStart + mData.size();
339
340 if (mRepeat) {
Chih-Chung Chang78979fc2011-09-09 16:41:54 +0800341 int count = mMediaSet.getMediaItemCount();
342 if (count == 0) return null;
343 index = index % count;
Owen Linf9a0a432011-08-17 22:07:43 +0800344 }
345 if (index < mDataStart || index >= dataEnd) {
346 mData = mMediaSet.getMediaItem(index, DATA_SIZE);
347 mDataStart = index;
348 dataEnd = index + mData.size();
Paramanandac12b8b12015-03-24 17:51:29 +0530349
350 // Consume license once in each element of the slide-show
351 // This is a non-blocking loop operation
Anand Chaudhari922a2fa2015-09-23 18:01:06 +0530352// for (int i = 0; i < mData.size(); i++) {
353// String path = mData.get(i).getFilePath();
354// if (DrmHelper.isDrmFile(path)) {
355// DrmHelper.consumeDrmRights(path, "image/*");
356// }
357// }
Owen Linf9a0a432011-08-17 22:07:43 +0800358 }
359
Ray Chen604f0532011-10-21 16:07:12 +0800360 return (index < mDataStart || index >= dataEnd) ? null : mData.get(index - mDataStart);
Owen Linf9a0a432011-08-17 22:07:43 +0800361 }
362
Ahbong Chang78179792012-07-30 11:34:13 +0800363 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800364 public long reload() {
John Reck705dc812013-03-21 14:22:33 -0700365 long version = mMediaSet.reload();
Owen Linf9a0a432011-08-17 22:07:43 +0800366 if (version != mDataVersion) {
367 mDataVersion = version;
368 mData.clear();
369 }
370 return mDataVersion;
371 }
372
Ahbong Chang78179792012-07-30 11:34:13 +0800373 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800374 public void addContentListener(ContentListener listener) {
375 mMediaSet.addContentListener(listener);
376 }
377
Ahbong Chang78179792012-07-30 11:34:13 +0800378 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800379 public void removeContentListener(ContentListener listener) {
380 mMediaSet.removeContentListener(listener);
381 }
382 }
383}