blob: 87ff5579d985df48b32f6b96e30b8134f354e200 [file] [log] [blame]
Owen Lina2fba682011-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.ui;
18
Ray Chen73e791c2011-10-04 15:19:44 +080019import android.graphics.Bitmap;
20import android.graphics.Color;
21import android.os.Message;
22
Owen Lina2fba682011-08-17 22:07:43 +080023import com.android.gallery3d.R;
24import com.android.gallery3d.app.GalleryActivity;
25import com.android.gallery3d.common.Utils;
26import com.android.gallery3d.data.MediaItem;
27import com.android.gallery3d.data.MediaSet;
28import com.android.gallery3d.data.Path;
29import com.android.gallery3d.ui.AlbumSetView.AlbumSetItem;
30import com.android.gallery3d.util.Future;
31import com.android.gallery3d.util.FutureListener;
Chih-Chung Chang70a73a72011-09-19 11:09:39 +080032import com.android.gallery3d.util.GalleryUtils;
Owen Lina2fba682011-08-17 22:07:43 +080033import com.android.gallery3d.util.MediaSetUtils;
34import com.android.gallery3d.util.ThreadPool;
35
Owen Lina2fba682011-08-17 22:07:43 +080036public class AlbumSetSlidingWindow implements AlbumSetView.ModelListener {
37 private static final String TAG = "GallerySlidingWindow";
38 private static final int MSG_LOAD_BITMAP_DONE = 0;
Chih-Chung Chang1b2af5e2011-09-27 19:44:36 +080039 private static final int PLACEHOLDER_COLOR = 0xFF222222;
Owen Lina2fba682011-08-17 22:07:43 +080040
41 public static interface Listener {
42 public void onSizeChanged(int size);
43 public void onContentInvalidated();
44 public void onWindowContentChanged(
45 int slot, AlbumSetItem old, AlbumSetItem update);
46 }
47
48 private final AlbumSetView.Model mSource;
49 private int mSize;
Ray Chen73e791c2011-10-04 15:19:44 +080050 private final AlbumSetView.LabelSpec mLabelSpec;
Owen Lina2fba682011-08-17 22:07:43 +080051
52 private int mContentStart = 0;
53 private int mContentEnd = 0;
54
55 private int mActiveStart = 0;
56 private int mActiveEnd = 0;
57
58 private Listener mListener;
59
60 private final MyAlbumSetItem mData[];
61 private SelectionDrawer mSelectionDrawer;
62 private final ColorTexture mWaitLoadingTexture;
63
Ray Chen73e791c2011-10-04 15:19:44 +080064 private final SynchronizedHandler mHandler;
65 private final ThreadPool mThreadPool;
Owen Lina2fba682011-08-17 22:07:43 +080066
67 private int mActiveRequestCount = 0;
Ray Chen73e791c2011-10-04 15:19:44 +080068 private final String mLoadingLabel;
Owen Lina2fba682011-08-17 22:07:43 +080069 private boolean mIsActive = false;
70
71 private static class MyAlbumSetItem extends AlbumSetItem {
72 public Path setPath;
73 public int sourceType;
74 public int cacheFlag;
75 public int cacheStatus;
76 }
77
Chih-Chung Chang07069de2011-09-14 20:50:28 +080078 public AlbumSetSlidingWindow(GalleryActivity activity,
79 AlbumSetView.LabelSpec labelSpec, SelectionDrawer drawer,
Owen Lina2fba682011-08-17 22:07:43 +080080 AlbumSetView.Model source, int cacheSize) {
81 source.setModelListener(this);
Chih-Chung Chang07069de2011-09-14 20:50:28 +080082 mLabelSpec = labelSpec;
Owen Lina2fba682011-08-17 22:07:43 +080083 mLoadingLabel = activity.getAndroidContext().getString(R.string.loading);
84 mSource = source;
85 mSelectionDrawer = drawer;
86 mData = new MyAlbumSetItem[cacheSize];
87 mSize = source.size();
88
Chih-Chung Chang1b2af5e2011-09-27 19:44:36 +080089 mWaitLoadingTexture = new ColorTexture(PLACEHOLDER_COLOR);
Owen Lina2fba682011-08-17 22:07:43 +080090 mWaitLoadingTexture.setSize(1, 1);
91
92 mHandler = new SynchronizedHandler(activity.getGLRoot()) {
93 @Override
94 public void handleMessage(Message message) {
95 Utils.assertTrue(message.what == MSG_LOAD_BITMAP_DONE);
96 ((GalleryDisplayItem) message.obj).onLoadBitmapDone();
97 }
98 };
99
100 mThreadPool = activity.getThreadPool();
101 }
102
103 public void setSelectionDrawer(SelectionDrawer drawer) {
104 mSelectionDrawer = drawer;
105 }
106
107 public void setListener(Listener listener) {
108 mListener = listener;
109 }
110
111 public AlbumSetItem get(int slotIndex) {
112 Utils.assertTrue(isActiveSlot(slotIndex),
113 "invalid slot: %s outsides (%s, %s)",
114 slotIndex, mActiveStart, mActiveEnd);
115 return mData[slotIndex % mData.length];
116 }
117
118 public int size() {
119 return mSize;
120 }
121
122 public boolean isActiveSlot(int slotIndex) {
123 return slotIndex >= mActiveStart && slotIndex < mActiveEnd;
124 }
125
126 private void setContentWindow(int contentStart, int contentEnd) {
127 if (contentStart == mContentStart && contentEnd == mContentEnd) return;
128
129 if (contentStart >= mContentEnd || mContentStart >= contentEnd) {
130 for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
131 freeSlotContent(i);
132 }
133 mSource.setActiveWindow(contentStart, contentEnd);
134 for (int i = contentStart; i < contentEnd; ++i) {
135 prepareSlotContent(i);
136 }
137 } else {
138 for (int i = mContentStart; i < contentStart; ++i) {
139 freeSlotContent(i);
140 }
141 for (int i = contentEnd, n = mContentEnd; i < n; ++i) {
142 freeSlotContent(i);
143 }
144 mSource.setActiveWindow(contentStart, contentEnd);
145 for (int i = contentStart, n = mContentStart; i < n; ++i) {
146 prepareSlotContent(i);
147 }
148 for (int i = mContentEnd; i < contentEnd; ++i) {
149 prepareSlotContent(i);
150 }
151 }
152
153 mContentStart = contentStart;
154 mContentEnd = contentEnd;
155 }
156
157 public void setActiveWindow(int start, int end) {
158 Utils.assertTrue(
159 start <= end && end - start <= mData.length && end <= mSize,
160 "start = %s, end = %s, length = %s, size = %s",
161 start, end, mData.length, mSize);
162
163 AlbumSetItem data[] = mData;
164
165 mActiveStart = start;
166 mActiveEnd = end;
167
Owen Lina2fba682011-08-17 22:07:43 +0800168 int contentStart = Utils.clamp((start + end) / 2 - data.length / 2,
169 0, Math.max(0, mSize - data.length));
170 int contentEnd = Math.min(contentStart + data.length, mSize);
171 setContentWindow(contentStart, contentEnd);
172 if (mIsActive) updateAllImageRequests();
173 }
174
175 // We would like to request non active slots in the following order:
176 // Order: 8 6 4 2 1 3 5 7
177 // |---------|---------------|---------|
178 // |<- active ->|
179 // |<-------- cached range ----------->|
180 private void requestNonactiveImages() {
181 int range = Math.max(
182 mContentEnd - mActiveEnd, mActiveStart - mContentStart);
183 for (int i = 0 ;i < range; ++i) {
184 requestImagesInSlot(mActiveEnd + i);
185 requestImagesInSlot(mActiveStart - 1 - i);
186 }
187 }
188
189 private void cancelNonactiveImages() {
190 int range = Math.max(
191 mContentEnd - mActiveEnd, mActiveStart - mContentStart);
192 for (int i = 0 ;i < range; ++i) {
193 cancelImagesInSlot(mActiveEnd + i);
194 cancelImagesInSlot(mActiveStart - 1 - i);
195 }
196 }
197
198 private void requestImagesInSlot(int slotIndex) {
199 if (slotIndex < mContentStart || slotIndex >= mContentEnd) return;
200 AlbumSetItem items = mData[slotIndex % mData.length];
201 for (DisplayItem item : items.covers) {
202 ((GalleryDisplayItem) item).requestImage();
203 }
204 }
205
206 private void cancelImagesInSlot(int slotIndex) {
207 if (slotIndex < mContentStart || slotIndex >= mContentEnd) return;
208 AlbumSetItem items = mData[slotIndex % mData.length];
209 for (DisplayItem item : items.covers) {
210 ((GalleryDisplayItem) item).cancelImageRequest();
211 }
212 }
213
214 private void freeSlotContent(int slotIndex) {
215 AlbumSetItem data[] = mData;
216 int index = slotIndex % data.length;
217 AlbumSetItem original = data[index];
218 if (original != null) {
219 data[index] = null;
220 for (DisplayItem item : original.covers) {
221 ((GalleryDisplayItem) item).recycle();
222 }
223 }
224 }
225
226 private long getMediaSetDataVersion(MediaSet set) {
227 return set == null
228 ? MediaSet.INVALID_DATA_VERSION
229 : set.getDataVersion();
230 }
231
232 private void prepareSlotContent(int slotIndex) {
233 MediaSet set = mSource.getMediaSet(slotIndex);
234
235 MyAlbumSetItem item = new MyAlbumSetItem();
236 MediaItem[] coverItems = mSource.getCoverItems(slotIndex);
237 item.covers = new GalleryDisplayItem[coverItems.length];
238 item.sourceType = identifySourceType(set);
239 item.cacheFlag = identifyCacheFlag(set);
240 item.cacheStatus = identifyCacheStatus(set);
241 item.setPath = set == null ? null : set.getPath();
242
243 for (int i = 0; i < coverItems.length; ++i) {
244 item.covers[i] = new GalleryDisplayItem(slotIndex, i, coverItems[i]);
245 }
246 item.labelItem = new LabelDisplayItem(slotIndex);
247 item.setDataVersion = getMediaSetDataVersion(set);
248 mData[slotIndex % mData.length] = item;
249 }
250
251 private boolean isCoverItemsChanged(int slotIndex) {
252 AlbumSetItem original = mData[slotIndex % mData.length];
253 if (original == null) return true;
254 MediaItem[] coverItems = mSource.getCoverItems(slotIndex);
255
256 if (original.covers.length != coverItems.length) return true;
257 for (int i = 0, n = coverItems.length; i < n; ++i) {
258 GalleryDisplayItem g = (GalleryDisplayItem) original.covers[i];
259 if (g.mDataVersion != coverItems[i].getDataVersion()) return true;
260 }
261 return false;
262 }
263
264 private void updateSlotContent(final int slotIndex) {
265
266 MyAlbumSetItem data[] = mData;
267 int pos = slotIndex % data.length;
268 MyAlbumSetItem original = data[pos];
269
270 if (!isCoverItemsChanged(slotIndex)) {
271 MediaSet set = mSource.getMediaSet(slotIndex);
272 original.sourceType = identifySourceType(set);
273 original.cacheFlag = identifyCacheFlag(set);
274 original.cacheStatus = identifyCacheStatus(set);
275 original.setPath = set == null ? null : set.getPath();
276 ((LabelDisplayItem) original.labelItem).updateContent();
277 if (mListener != null) mListener.onContentInvalidated();
278 return;
279 }
280
281 prepareSlotContent(slotIndex);
282 AlbumSetItem update = data[pos];
283
284 if (mListener != null && isActiveSlot(slotIndex)) {
285 mListener.onWindowContentChanged(slotIndex, original, update);
286 }
287 if (original != null) {
288 for (DisplayItem item : original.covers) {
289 ((GalleryDisplayItem) item).recycle();
290 }
291 }
292 }
293
294 private void notifySlotChanged(int slotIndex) {
295 // If the updated content is not cached, ignore it
296 if (slotIndex < mContentStart || slotIndex >= mContentEnd) {
297 Log.w(TAG, String.format(
298 "invalid update: %s is outside (%s, %s)",
299 slotIndex, mContentStart, mContentEnd) );
300 return;
301 }
302 updateSlotContent(slotIndex);
303 boolean isActiveSlot = isActiveSlot(slotIndex);
304 if (mActiveRequestCount == 0 || isActiveSlot) {
305 for (DisplayItem item : mData[slotIndex % mData.length].covers) {
306 GalleryDisplayItem galleryItem = (GalleryDisplayItem) item;
307 galleryItem.requestImage();
308 if (isActiveSlot && galleryItem.isRequestInProgress()) {
309 ++mActiveRequestCount;
310 }
311 }
312 }
313 }
314
315 private void updateAllImageRequests() {
316 mActiveRequestCount = 0;
317 for (int i = mActiveStart, n = mActiveEnd; i < n; ++i) {
318 for (DisplayItem item : mData[i % mData.length].covers) {
319 GalleryDisplayItem coverItem = (GalleryDisplayItem) item;
320 coverItem.requestImage();
321 if (coverItem.isRequestInProgress()) ++mActiveRequestCount;
322 }
323 }
324 if (mActiveRequestCount == 0) {
325 requestNonactiveImages();
326 } else {
327 cancelNonactiveImages();
328 }
329 }
330
331 private class GalleryDisplayItem extends AbstractDisplayItem
332 implements FutureListener<Bitmap> {
333 private Future<Bitmap> mFuture;
334 private final int mSlotIndex;
335 private final int mCoverIndex;
336 private final int mMediaType;
337 private Texture mContent;
338 private final long mDataVersion;
Ray Chen73e791c2011-10-04 15:19:44 +0800339 private final boolean mIsPanorama;
Chih-Chung Changffaaec32011-09-29 13:16:48 +0800340 private boolean mWaitLoadingDisplayed;
Owen Lina2fba682011-08-17 22:07:43 +0800341
342 public GalleryDisplayItem(int slotIndex, int coverIndex, MediaItem item) {
343 super(item);
344 mSlotIndex = slotIndex;
345 mCoverIndex = coverIndex;
346 mMediaType = item.getMediaType();
347 mDataVersion = item.getDataVersion();
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800348 mIsPanorama = GalleryUtils.isPanorama(item);
Owen Lina2fba682011-08-17 22:07:43 +0800349 updateContent(mWaitLoadingTexture);
350 }
351
352 @Override
353 protected void onBitmapAvailable(Bitmap bitmap) {
354 if (isActiveSlot(mSlotIndex)) {
355 --mActiveRequestCount;
356 if (mActiveRequestCount == 0) requestNonactiveImages();
357 }
358 if (bitmap != null) {
Chih-Chung Change3312ff2011-09-22 14:55:32 +0800359 BitmapTexture texture = new BitmapTexture(bitmap, true);
Owen Lina2fba682011-08-17 22:07:43 +0800360 texture.setThrottled(true);
Chih-Chung Changffaaec32011-09-29 13:16:48 +0800361 if (mWaitLoadingDisplayed) {
362 updateContent(new FadeInTexture(PLACEHOLDER_COLOR, texture));
363 } else {
364 updateContent(texture);
365 }
Owen Lina2fba682011-08-17 22:07:43 +0800366 if (mListener != null) mListener.onContentInvalidated();
367 }
368 }
369
370 private void updateContent(Texture content) {
371 mContent = content;
Owen Lina2fba682011-08-17 22:07:43 +0800372 }
373
374 @Override
Chih-Chung Chang1b2af5e2011-09-27 19:44:36 +0800375 public int render(GLCanvas canvas, int pass) {
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800376 // Fit the content into the box
377 int width = mContent.getWidth();
378 int height = mContent.getHeight();
379
380 float scalex = mBoxWidth / (float) width;
381 float scaley = mBoxHeight / (float) height;
382 float scale = Math.min(scalex, scaley);
383
Chih-Chung Chang1e33de92012-02-10 17:08:58 -0800384 width = (int) Math.floor(width * scale);
385 height = (int) Math.floor(height * scale);
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800386
387 // Now draw it
Owen Lina2fba682011-08-17 22:07:43 +0800388 int sourceType = SelectionDrawer.DATASOURCE_TYPE_NOT_CATEGORIZED;
389 int cacheFlag = MediaSet.CACHE_FLAG_NO;
390 int cacheStatus = MediaSet.CACHE_STATUS_NOT_CACHED;
391 MyAlbumSetItem set = mData[mSlotIndex % mData.length];
392 Path path = set.setPath;
393 if (mCoverIndex == 0) {
394 sourceType = set.sourceType;
395 cacheFlag = set.cacheFlag;
396 cacheStatus = set.cacheStatus;
397 }
398
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800399 mSelectionDrawer.draw(canvas, mContent, width, height,
Chih-Chung Chang1b2af5e2011-09-27 19:44:36 +0800400 getRotation(), path, sourceType, mMediaType,
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800401 mIsPanorama, mLabelSpec.labelBackgroundHeight,
Owen Lina2fba682011-08-17 22:07:43 +0800402 cacheFlag == MediaSet.CACHE_FLAG_FULL,
403 (cacheFlag == MediaSet.CACHE_FLAG_FULL)
404 && (cacheStatus != MediaSet.CACHE_STATUS_CACHED_FULL));
Chih-Chung Chang1b2af5e2011-09-27 19:44:36 +0800405
Chih-Chung Changffaaec32011-09-29 13:16:48 +0800406 if (mContent == mWaitLoadingTexture) {
407 mWaitLoadingDisplayed = true;
408 }
409
410 if ((mContent instanceof FadeInTexture) &&
Chih-Chung Chang1b2af5e2011-09-27 19:44:36 +0800411 ((FadeInTexture) mContent).isAnimating()) {
412 return RENDER_MORE_FRAME;
413 } else {
414 return 0;
415 }
Owen Lina2fba682011-08-17 22:07:43 +0800416 }
417
418 @Override
419 public void startLoadBitmap() {
420 mFuture = mThreadPool.submit(mMediaItem.requestImage(
421 MediaItem.TYPE_MICROTHUMBNAIL), this);
422 }
423
424 @Override
425 public void cancelLoadBitmap() {
426 mFuture.cancel();
427 }
428
429 @Override
430 public void onFutureDone(Future<Bitmap> future) {
431 mHandler.sendMessage(mHandler.obtainMessage(MSG_LOAD_BITMAP_DONE, this));
432 }
433
434 private void onLoadBitmapDone() {
435 Future<Bitmap> future = mFuture;
436 mFuture = null;
437 updateImage(future.get(), future.isCancelled());
438 }
439
440 @Override
441 public String toString() {
442 return String.format("GalleryDisplayItem(%s, %s)", mSlotIndex, mCoverIndex);
443 }
444 }
445
446 private static int identifySourceType(MediaSet set) {
447 if (set == null) {
448 return SelectionDrawer.DATASOURCE_TYPE_NOT_CATEGORIZED;
449 }
450
451 Path path = set.getPath();
452 if (MediaSetUtils.isCameraSource(path)) {
453 return SelectionDrawer.DATASOURCE_TYPE_CAMERA;
454 }
455
456 int type = SelectionDrawer.DATASOURCE_TYPE_NOT_CATEGORIZED;
457 String prefix = path.getPrefix();
458
459 if (prefix.equals("picasa")) {
460 type = SelectionDrawer.DATASOURCE_TYPE_PICASA;
461 } else if (prefix.equals("local") || prefix.equals("merge")) {
462 type = SelectionDrawer.DATASOURCE_TYPE_LOCAL;
463 } else if (prefix.equals("mtp")) {
464 type = SelectionDrawer.DATASOURCE_TYPE_MTP;
465 }
466
467 return type;
468 }
469
470 private static int identifyCacheFlag(MediaSet set) {
471 if (set == null || (set.getSupportedOperations()
472 & MediaSet.SUPPORT_CACHE) == 0) {
473 return MediaSet.CACHE_FLAG_NO;
474 }
475
476 return set.getCacheFlag();
477 }
478
479 private static int identifyCacheStatus(MediaSet set) {
480 if (set == null || (set.getSupportedOperations()
481 & MediaSet.SUPPORT_CACHE) == 0) {
482 return MediaSet.CACHE_STATUS_NOT_CACHED;
483 }
484
485 return set.getCacheStatus();
486 }
487
488 private class LabelDisplayItem extends DisplayItem {
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800489 private static final int FONT_COLOR_TITLE = Color.WHITE;
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800490 private static final int FONT_COLOR_COUNT = 0x80FFFFFF; // 50% white
Owen Lina2fba682011-08-17 22:07:43 +0800491
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800492 private StringTexture mTextureTitle;
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800493 private StringTexture mTextureCount;
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800494 private String mTitle;
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800495 private String mCount;
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800496 private int mLastWidth;
Owen Lina2fba682011-08-17 22:07:43 +0800497 private final int mSlotIndex;
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800498 private boolean mHasIcon;
Owen Lina2fba682011-08-17 22:07:43 +0800499
500 public LabelDisplayItem(int slotIndex) {
501 mSlotIndex = slotIndex;
Owen Lina2fba682011-08-17 22:07:43 +0800502 }
503
504 public boolean updateContent() {
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800505 String title = mLoadingLabel;
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800506 String count = "";
Owen Lina2fba682011-08-17 22:07:43 +0800507 MediaSet set = mSource.getMediaSet(mSlotIndex);
508 if (set != null) {
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800509 title = Utils.ensureNotNull(set.getName());
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800510 count = "" + set.getTotalMediaItemCount();
Owen Lina2fba682011-08-17 22:07:43 +0800511 }
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800512 if (Utils.equals(title, mTitle)
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800513 && Utils.equals(count, mCount)
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800514 && Utils.equals(mBoxWidth, mLastWidth)) {
515 return false;
516 }
517 mTitle = title;
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800518 mCount = count;
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800519 mLastWidth = mBoxWidth;
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800520 mHasIcon = (identifySourceType(set) !=
521 SelectionDrawer.DATASOURCE_TYPE_NOT_CATEGORIZED);
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800522
523 AlbumSetView.LabelSpec s = mLabelSpec;
524 mTextureTitle = StringTexture.newInstance(
525 title, s.titleFontSize, FONT_COLOR_TITLE,
526 mBoxWidth - s.leftMargin, false);
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800527 mTextureCount = StringTexture.newInstance(
528 count, s.countFontSize, FONT_COLOR_COUNT,
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800529 mBoxWidth - s.leftMargin, true);
530
Owen Lina2fba682011-08-17 22:07:43 +0800531 return true;
532 }
533
534 @Override
Chih-Chung Chang1b2af5e2011-09-27 19:44:36 +0800535 public int render(GLCanvas canvas, int pass) {
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800536 if (mBoxWidth != mLastWidth) {
537 updateContent();
538 }
539
540 AlbumSetView.LabelSpec s = mLabelSpec;
541 int x = -mBoxWidth / 2;
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800542 int y = (mBoxHeight + 1) / 2 - s.labelBackgroundHeight;
Chih-Chung Chang07069de2011-09-14 20:50:28 +0800543 y += s.titleOffset;
544 mTextureTitle.draw(canvas, x + s.leftMargin, y);
Chih-Chung Chang70a73a72011-09-19 11:09:39 +0800545 y += s.titleFontSize + s.countOffset;
546 x += mHasIcon ? s.iconSize : s.leftMargin;
547 mTextureCount.draw(canvas, x, y);
Chih-Chung Chang1b2af5e2011-09-27 19:44:36 +0800548 return 0;
Owen Lina2fba682011-08-17 22:07:43 +0800549 }
550
551 @Override
552 public long getIdentity() {
553 return System.identityHashCode(this);
554 }
555 }
556
557 public void onSizeChanged(int size) {
Ray Chen73e791c2011-10-04 15:19:44 +0800558 if (mIsActive && mSize != size) {
Owen Lina2fba682011-08-17 22:07:43 +0800559 mSize = size;
Ray Chen73e791c2011-10-04 15:19:44 +0800560 if (mListener != null) mListener.onSizeChanged(mSize);
Owen Lina2fba682011-08-17 22:07:43 +0800561 }
562 }
563
564 public void onWindowContentChanged(int index) {
565 if (!mIsActive) {
566 // paused, ignore slot changed event
567 return;
568 }
569 notifySlotChanged(index);
570 }
571
572 public void pause() {
573 mIsActive = false;
574 for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
575 freeSlotContent(i);
576 }
577 }
578
579 public void resume() {
580 mIsActive = true;
581 for (int i = mContentStart, n = mContentEnd; i < n; ++i) {
582 prepareSlotContent(i);
583 }
584 updateAllImageRequests();
585 }
586}