blob: 2923ee9984394e5bbce80d34498a4770a7070422 [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();
Joey Rizzoli0a421722016-06-01 14:04:38 +0200179 ((GalleryActivity) mActivity).toggleNavBar(true);
Owen Linf9a0a432011-08-17 22:07:43 +0800180 mIsActive = false;
181 mModel.pause();
182 mSlideshowView.release();
183
184 mHandler.removeMessages(MSG_LOAD_NEXT_BITMAP);
185 mHandler.removeMessages(MSG_SHOW_PENDING_BITMAP);
186 }
187
188 @Override
189 public void onResume() {
190 super.onResume();
Joey Rizzoli0a421722016-06-01 14:04:38 +0200191 ((GalleryActivity) mActivity).toggleNavBar(false);
Owen Linf9a0a432011-08-17 22:07:43 +0800192 mIsActive = true;
193 mModel.resume();
194
195 if (mPendingSlide != null) {
196 showPendingBitmap();
197 } else {
198 loadNextBitmap();
199 }
200 }
201
202 private void initializeData(Bundle data) {
Owen Linf9a0a432011-08-17 22:07:43 +0800203 boolean random = data.getBoolean(KEY_RANDOM_ORDER, false);
Chih-Chung Chang78979fc2011-09-09 16:41:54 +0800204
205 // We only want to show slideshow for images only, not videos.
206 String mediaPath = data.getString(KEY_SET_PATH);
Ray Chen604f0532011-10-21 16:07:12 +0800207 mediaPath = FilterUtils.newFilterPath(mediaPath, FilterUtils.FILTER_IMAGE_ONLY);
Owen Linf9a0a432011-08-17 22:07:43 +0800208 MediaSet mediaSet = mActivity.getDataManager().getMediaSet(mediaPath);
209
210 if (random) {
211 boolean repeat = data.getBoolean(KEY_REPEAT);
Ray Chen604f0532011-10-21 16:07:12 +0800212 mModel = new SlideshowDataAdapter(mActivity,
213 new ShuffleSource(mediaSet, repeat), 0, null);
214 setStateResult(Activity.RESULT_OK, mResultIntent.putExtra(KEY_PHOTO_INDEX, 0));
Owen Linf9a0a432011-08-17 22:07:43 +0800215 } else {
216 int index = data.getInt(KEY_PHOTO_INDEX);
Ray Chen50620062011-11-03 15:47:38 +0800217 String itemPath = data.getString(KEY_ITEM_PATH);
218 Path path = itemPath != null ? Path.fromString(itemPath) : null;
Owen Linf9a0a432011-08-17 22:07:43 +0800219 boolean repeat = data.getBoolean(KEY_REPEAT);
Ray Chen604f0532011-10-21 16:07:12 +0800220 mModel = new SlideshowDataAdapter(mActivity, new SequentialSource(mediaSet, repeat),
221 index, path);
222 setStateResult(Activity.RESULT_OK, mResultIntent.putExtra(KEY_PHOTO_INDEX, index));
Owen Linf9a0a432011-08-17 22:07:43 +0800223 }
224 }
225
226 private void initializeViews() {
227 mSlideshowView = new SlideshowView();
228 mRootPane.addComponent(mSlideshowView);
229 setContentPane(mRootPane);
230 }
231
232 private static MediaItem findMediaItem(MediaSet mediaSet, int index) {
233 for (int i = 0, n = mediaSet.getSubMediaSetCount(); i < n; ++i) {
234 MediaSet subset = mediaSet.getSubMediaSet(i);
235 int count = subset.getTotalMediaItemCount();
236 if (index < count) {
237 return findMediaItem(subset, index);
238 }
239 index -= count;
240 }
241 ArrayList<MediaItem> list = mediaSet.getMediaItem(index, 1);
242 return list.isEmpty() ? null : list.get(0);
243 }
244
245 private static class ShuffleSource implements SlideshowDataAdapter.SlideshowSource {
246 private static final int RETRY_COUNT = 5;
247 private final MediaSet mMediaSet;
248 private final Random mRandom = new Random();
249 private int mOrder[] = new int[0];
Ray Chen604f0532011-10-21 16:07:12 +0800250 private final boolean mRepeat;
Owen Linf9a0a432011-08-17 22:07:43 +0800251 private long mSourceVersion = MediaSet.INVALID_DATA_VERSION;
252 private int mLastIndex = -1;
253
254 public ShuffleSource(MediaSet mediaSet, boolean repeat) {
255 mMediaSet = Utils.checkNotNull(mediaSet);
256 mRepeat = repeat;
257 }
258
Ahbong Chang78179792012-07-30 11:34:13 +0800259 @Override
Ray Chen604f0532011-10-21 16:07:12 +0800260 public int findItemIndex(Path path, int hint) {
261 return hint;
262 }
263
Ahbong Chang78179792012-07-30 11:34:13 +0800264 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800265 public MediaItem getMediaItem(int index) {
266 if (!mRepeat && index >= mOrder.length) return null;
Chih-Chung Chang78979fc2011-09-09 16:41:54 +0800267 if (mOrder.length == 0) return null;
Owen Linf9a0a432011-08-17 22:07:43 +0800268 mLastIndex = mOrder[index % mOrder.length];
269 MediaItem item = findMediaItem(mMediaSet, mLastIndex);
270 for (int i = 0; i < RETRY_COUNT && item == null; ++i) {
271 Log.w(TAG, "fail to find image: " + mLastIndex);
272 mLastIndex = mRandom.nextInt(mOrder.length);
273 item = findMediaItem(mMediaSet, mLastIndex);
274 }
275 return item;
276 }
277
Ahbong Chang78179792012-07-30 11:34:13 +0800278 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800279 public long reload() {
John Reck705dc812013-03-21 14:22:33 -0700280 long version = mMediaSet.reload();
Owen Linf9a0a432011-08-17 22:07:43 +0800281 if (version != mSourceVersion) {
282 mSourceVersion = version;
283 int count = mMediaSet.getTotalMediaItemCount();
284 if (count != mOrder.length) generateOrderArray(count);
285 }
286 return version;
287 }
288
289 private void generateOrderArray(int totalCount) {
290 if (mOrder.length != totalCount) {
291 mOrder = new int[totalCount];
292 for (int i = 0; i < totalCount; ++i) {
293 mOrder[i] = i;
294 }
295 }
296 for (int i = totalCount - 1; i > 0; --i) {
297 Utils.swap(mOrder, i, mRandom.nextInt(i + 1));
298 }
299 if (mOrder[0] == mLastIndex && totalCount > 1) {
300 Utils.swap(mOrder, 0, mRandom.nextInt(totalCount - 1) + 1);
301 }
302 }
303
Ahbong Chang78179792012-07-30 11:34:13 +0800304 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800305 public void addContentListener(ContentListener listener) {
306 mMediaSet.addContentListener(listener);
307 }
308
Ahbong Chang78179792012-07-30 11:34:13 +0800309 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800310 public void removeContentListener(ContentListener listener) {
311 mMediaSet.removeContentListener(listener);
312 }
313 }
314
315 private static class SequentialSource implements SlideshowDataAdapter.SlideshowSource {
316 private static final int DATA_SIZE = 32;
317
318 private ArrayList<MediaItem> mData = new ArrayList<MediaItem>();
319 private int mDataStart = 0;
320 private long mDataVersion = MediaObject.INVALID_DATA_VERSION;
321 private final MediaSet mMediaSet;
322 private final boolean mRepeat;
323
324 public SequentialSource(MediaSet mediaSet, boolean repeat) {
325 mMediaSet = mediaSet;
326 mRepeat = repeat;
327 }
328
Ahbong Chang78179792012-07-30 11:34:13 +0800329 @Override
Ray Chen604f0532011-10-21 16:07:12 +0800330 public int findItemIndex(Path path, int hint) {
331 return mMediaSet.getIndexOfItem(path, hint);
332 }
333
Ahbong Chang78179792012-07-30 11:34:13 +0800334 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800335 public MediaItem getMediaItem(int index) {
336 int dataEnd = mDataStart + mData.size();
337
338 if (mRepeat) {
Chih-Chung Chang78979fc2011-09-09 16:41:54 +0800339 int count = mMediaSet.getMediaItemCount();
340 if (count == 0) return null;
341 index = index % count;
Owen Linf9a0a432011-08-17 22:07:43 +0800342 }
343 if (index < mDataStart || index >= dataEnd) {
344 mData = mMediaSet.getMediaItem(index, DATA_SIZE);
345 mDataStart = index;
346 dataEnd = index + mData.size();
Paramanandac12b8b12015-03-24 17:51:29 +0530347
348 // Consume license once in each element of the slide-show
349 // This is a non-blocking loop operation
Anand Chaudhari922a2fa2015-09-23 18:01:06 +0530350// for (int i = 0; i < mData.size(); i++) {
351// String path = mData.get(i).getFilePath();
352// if (DrmHelper.isDrmFile(path)) {
353// DrmHelper.consumeDrmRights(path, "image/*");
354// }
355// }
Owen Linf9a0a432011-08-17 22:07:43 +0800356 }
357
Ray Chen604f0532011-10-21 16:07:12 +0800358 return (index < mDataStart || index >= dataEnd) ? null : mData.get(index - mDataStart);
Owen Linf9a0a432011-08-17 22:07:43 +0800359 }
360
Ahbong Chang78179792012-07-30 11:34:13 +0800361 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800362 public long reload() {
John Reck705dc812013-03-21 14:22:33 -0700363 long version = mMediaSet.reload();
Owen Linf9a0a432011-08-17 22:07:43 +0800364 if (version != mDataVersion) {
365 mDataVersion = version;
366 mData.clear();
367 }
368 return mDataVersion;
369 }
370
Ahbong Chang78179792012-07-30 11:34:13 +0800371 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800372 public void addContentListener(ContentListener listener) {
373 mMediaSet.addContentListener(listener);
374 }
375
Ahbong Chang78179792012-07-30 11:34:13 +0800376 @Override
Owen Linf9a0a432011-08-17 22:07:43 +0800377 public void removeContentListener(ContentListener listener) {
378 mMediaSet.removeContentListener(listener);
379 }
380 }
381}