private boolean needContentReload() { for (int i = mContentStart, n = mContentEnd; i < n; ++i) { if (mData[i % DATA_CACHE_SIZE] == null) return true; } MediaItem current = mData[mCurrentIndex % DATA_CACHE_SIZE]; return current == null || current.getPath() != mItemPath; }
private void updateImageCache() { HashSet<Long> toBeRemoved = new HashSet<Long>(mImageCache.keySet()); for (int i = mActiveStart; i < mActiveEnd; ++i) { MediaItem item = mData[i % DATA_CACHE_SIZE]; long version = item == null ? MediaObject.INVALID_DATA_VERSION : item.getDataVersion(); if (version == MediaObject.INVALID_DATA_VERSION) continue; ImageEntry entry = mImageCache.get(version); toBeRemoved.remove(version); if (entry != null) { if (Math.abs(i - mCurrentIndex) > 1) { if (entry.fullImageTask != null) { entry.fullImageTask.cancel(); entry.fullImageTask = null; } entry.fullImage = null; entry.requestedBits &= ~BIT_FULL_IMAGE; } } else { entry = new ImageEntry(); entry.rotation = item.getFullImageRotation(); mImageCache.put(version, entry); } } // Clear the data and requests for ImageEntries outside the new window. for (Long version : toBeRemoved) { ImageEntry entry = mImageCache.remove(version); if (entry.fullImageTask != null) entry.fullImageTask.cancel(); if (entry.screenNailTask != null) entry.screenNailTask.cancel(); } }
@Override public void run() { while (mActive) { synchronized (this) { if (!mDirty && mActive) { updateLoading(false); Utils.waitWithoutInterrupt(this); continue; } } mDirty = false; UpdateInfo info = executeAndWait(new GetUpdateInfo()); synchronized (DataManager.LOCK) { updateLoading(true); long version = mSource.reload(); if (info.version != version) { info.reloadContent = true; info.size = mSource.getMediaItemCount(); } if (!info.reloadContent) continue; info.items = mSource.getMediaItem(info.contentStart, info.contentEnd); MediaItem item = findCurrentMediaItem(info); if (item == null || item.getPath() != info.target) { info.indexHint = findIndexOfTarget(info); } } executeAndWait(new UpdateContent(info)); } }
// Returns the task if we started the task or the task is already started. private Future<?> startTaskIfNeeded(int index, int which) { if (index < mActiveStart || index >= mActiveEnd) return null; ImageEntry entry = mImageCache.get(getVersion(index)); if (entry == null) return null; if (which == BIT_SCREEN_NAIL && entry.screenNailTask != null) { return entry.screenNailTask; } else if (which == BIT_FULL_IMAGE && entry.fullImageTask != null) { return entry.fullImageTask; } MediaItem item = mData[index % DATA_CACHE_SIZE]; Utils.assertTrue(item != null); if (which == BIT_SCREEN_NAIL && (entry.requestedBits & BIT_SCREEN_NAIL) == 0) { entry.requestedBits |= BIT_SCREEN_NAIL; entry.screenNailTask = mThreadPool.submit( new ScreenNailJob(item), new ScreenNailListener(item.getDataVersion())); // request screen nail return entry.screenNailTask; } if (which == BIT_FULL_IMAGE && (entry.requestedBits & BIT_FULL_IMAGE) == 0 && (item.getSupportedOperations() & MediaItem.SUPPORT_FULL_IMAGE) != 0) { entry.requestedBits |= BIT_FULL_IMAGE; entry.fullImageTask = mThreadPool.submit( item.requestLargeImage(), new FullImageListener(item.getDataVersion())); // request full image return entry.fullImageTask; } return null; }
private void updateImageRequests() { if (!mIsActive) return; int currentIndex = mCurrentIndex; MediaItem item = mData[currentIndex % DATA_CACHE_SIZE]; if (item == null || item.getPath() != mItemPath) { // current item mismatch - don't request image return; } // 1. Find the most wanted request and start it (if not already started). Future<?> task = null; for (int i = 0; i < sImageFetchSeq.length; i++) { int offset = sImageFetchSeq[i].indexOffset; int bit = sImageFetchSeq[i].imageBit; task = startTaskIfNeeded(currentIndex + offset, bit); if (task != null) break; } // 2. Cancel everything else. for (ImageEntry entry : mImageCache.values()) { if (entry.screenNailTask != null && entry.screenNailTask != task) { entry.screenNailTask.cancel(); entry.screenNailTask = null; entry.requestedBits &= ~BIT_SCREEN_NAIL; } if (entry.fullImageTask != null && entry.fullImageTask != task) { entry.fullImageTask.cancel(); entry.fullImageTask = null; entry.requestedBits &= ~BIT_FULL_IMAGE; } } }
private long getVersion(int index) { if (index < 0 || index >= mSize) return VERSION_OUT_OF_RANGE; if (index >= mContentStart && index < mContentEnd) { MediaItem item = mData[index % DATA_CACHE_SIZE]; if (item != null) return item.getDataVersion(); } return MediaObject.INVALID_DATA_VERSION; }
public void onLongTap(int slotIndex) { if (mGetContent) return; MediaItem item = mAlbumDataAdapter.get(slotIndex); if (item == null) return; mSelectionManager.setAutoLeaveSelectionMode(true); mSelectionManager.toggle(item.getPath()); mSlotView.invalidate(); }
@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 public Bitmap run(JobContext jc) { Bitmap bitmap = mItem.requestImage(MediaItem.TYPE_THUMBNAIL).run(jc); if (jc.isCancelled()) return null; if (bitmap != null) { bitmap = BitmapUtils.rotateBitmap( bitmap, mItem.getRotation() - mItem.getFullImageRotation(), true); } return bitmap; }
private boolean execute(DataManager manager, JobContext jc, int cmd, Path path) { boolean result = true; Log.v(TAG, "Execute cmd: " + cmd + " for " + path); long startTime = System.currentTimeMillis(); switch (cmd) { case R.id.action_delete: manager.delete(path); break; case R.id.action_rotate_cw: manager.rotate(path, 90); break; case R.id.action_rotate_ccw: manager.rotate(path, -90); break; case R.id.action_toggle_full_caching: { MediaObject obj = manager.getMediaObject(path); int cacheFlag = obj.getCacheFlag(); if (cacheFlag == MediaObject.CACHE_FLAG_FULL) { cacheFlag = MediaObject.CACHE_FLAG_SCREENNAIL; } else { cacheFlag = MediaObject.CACHE_FLAG_FULL; } obj.cache(cacheFlag); break; } case R.id.action_show_on_map: { MediaItem item = (MediaItem) manager.getMediaObject(path); double latlng[] = new double[2]; item.getLatLong(latlng); if (GalleryUtils.isValidLocation(latlng[0], latlng[1])) { GalleryUtils.showOnMap((Context) mActivity, latlng[0], latlng[1]); } break; } case R.id.action_import: { MediaObject obj = manager.getMediaObject(path); result = obj.Import(); break; } default: throw new AssertionError(); } Log.v( TAG, "It takes " + (System.currentTimeMillis() - startTime) + " ms to execute cmd for " + path); return result; }
public void setCurrentPhoto(Path path, int indexHint) { if (mItemPath == path) return; mItemPath = path; mCurrentIndex = indexHint; updateSlidingWindow(); updateImageCache(); fireModelInvalidated(); // We need to reload content if the path doesn't match. MediaItem item = getCurrentMediaItem(); if (item != null && item.getPath() != path) { if (mReloadTask != null) mReloadTask.notifyDirty(); } }
private void onSingleTapUp(int slotIndex) { 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); } }
private void updateCurrentIndex(int index) { mCurrentIndex = index; updateSlidingWindow(); MediaItem item = mData[index % DATA_CACHE_SIZE]; mItemPath = item == null ? null : item.getPath(); updateImageCache(); updateImageRequests(); updateTileProvider(); mPhotoView.notifyOnNewImage(); if (mDataListener != null) { mDataListener.onPhotoChanged(index, mItemPath); } fireModelInvalidated(); }
@Override public Void call() throws Exception { UpdateInfo info = mUpdateInfo; mSourceVersion = info.version; if (info.size != mSize) { mSize = info.size; if (mContentEnd > mSize) mContentEnd = mSize; if (mActiveEnd > mSize) mActiveEnd = mSize; } if (info.indexHint == MediaSet.INDEX_NOT_FOUND) { // The image has been deleted, clear mItemPath, the // mCurrentIndex will be updated in the updateCurrentItem(). mItemPath = null; updateCurrentItem(); } else { mCurrentIndex = info.indexHint; } updateSlidingWindow(); if (info.items != null) { int start = Math.max(info.contentStart, mContentStart); int end = Math.min(info.contentStart + info.items.size(), mContentEnd); int dataIndex = start % DATA_CACHE_SIZE; for (int i = start; i < end; ++i) { mData[dataIndex] = info.items.get(i - info.contentStart); if (++dataIndex == DATA_CACHE_SIZE) dataIndex = 0; } } if (mItemPath == null) { MediaItem current = mData[mCurrentIndex % DATA_CACHE_SIZE]; mItemPath = current == null ? null : current.getPath(); } updateImageCache(); updateTileProvider(); updateImageRequests(); fireModelInvalidated(); return null; }
private void onGetContent(final MediaItem item) { DataManager dm = mActivity.getDataManager(); Activity activity = mActivity; if (mData.getString(GalleryActivity.EXTRA_CROP) != null) { Uri uri = dm.getContentUri(item.getPath()); Intent intent = new Intent(CropActivity.CROP_ACTION, uri) .addFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT) .putExtras(getData()); if (mData.getParcelable(MediaStore.EXTRA_OUTPUT) == null) { intent.putExtra(CropExtras.KEY_RETURN_DATA, true); } activity.startActivity(intent); activity.finish(); } else { Intent intent = new Intent(null, item.getContentUri()).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); activity.setResult(Activity.RESULT_OK, intent); activity.finish(); } }
private void pickPhoto(int slotIndex, boolean startInFilmstrip) { if (!mIsActive) return; if (!startInFilmstrip) { // Launch photos in lights out mode mActivity.getGLRoot().setLightsOutMode(true); } MediaItem item = mAlbumDataAdapter.get(slotIndex); if (item == null) return; // Item not ready yet, ignore the click if (mGetContent) { onGetContent(item); } else if (mLaunchedFromPhotoPage) { TransitionStore transitions = mActivity.getTransitionStore(); transitions.put(PhotoPage.KEY_ALBUMPAGE_TRANSITION, PhotoPage.MSG_ALBUMPAGE_PICKED); transitions.put(PhotoPage.KEY_INDEX_HINT, slotIndex); onBackPressed(); } else { // Get into the PhotoPage. // mAlbumView.savePositions(PositionRepository.getInstance(mActivity)); Bundle data = new Bundle(); data.putInt(PhotoPage.KEY_INDEX_HINT, slotIndex); data.putParcelable( PhotoPage.KEY_OPEN_ANIMATION_RECT, mSlotView.getSlotRect(slotIndex, mRootPane)); data.putString(PhotoPage.KEY_MEDIA_SET_PATH, mMediaSetPath.toString()); data.putString(PhotoPage.KEY_MEDIA_ITEM_PATH, item.getPath().toString()); 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); } } }
public static boolean isPanorama(MediaItem item) { if (item == null) return false; int w = item.getWidth(); int h = item.getHeight(); return (h > 0 && w / h >= 2); }