summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBobby Georgescu <georgescu@google.com>2013-02-13 19:46:39 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2013-02-13 19:46:40 +0000
commitc81c9a87075e89acb940ff6cb1293b48ac7b1cb0 (patch)
treef368c894f93e47e789a359a6d02ea1b858b9de65 /src
parentbfa696afec98657e7fa321522d60fcc514ff2637 (diff)
parentc97dddfe187be8ecfde9f8914e8018102ec6209a (diff)
downloadandroid_packages_apps_Snap-c81c9a87075e89acb940ff6cb1293b48ac7b1cb0.tar.gz
android_packages_apps_Snap-c81c9a87075e89acb940ff6cb1293b48ac7b1cb0.tar.bz2
android_packages_apps_Snap-c81c9a87075e89acb940ff6cb1293b48ac7b1cb0.zip
Merge "Importer: Full-screen viewing, UI refinement, refactoring" into gb-ub-photos-bryce
Diffstat (limited to 'src')
-rw-r--r--src/com/android/gallery3d/ingest/IngestActivity.java230
-rw-r--r--src/com/android/gallery3d/ingest/IngestService.java24
-rw-r--r--src/com/android/gallery3d/ingest/MtpDeviceIndex.java105
-rw-r--r--src/com/android/gallery3d/ingest/adapter/CheckBroker.java56
-rw-r--r--src/com/android/gallery3d/ingest/adapter/MtpAdapter.java16
-rw-r--r--src/com/android/gallery3d/ingest/adapter/MtpPagerAdapter.java102
-rw-r--r--src/com/android/gallery3d/ingest/data/BitmapWithMetadata.java29
-rw-r--r--src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java97
-rw-r--r--src/com/android/gallery3d/ingest/ui/IngestGridView.java58
-rw-r--r--src/com/android/gallery3d/ingest/ui/MtpBitmapCache.java73
-rw-r--r--src/com/android/gallery3d/ingest/ui/MtpFullscreenView.java115
-rw-r--r--src/com/android/gallery3d/ingest/ui/MtpImageView.java130
-rw-r--r--src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java90
13 files changed, 907 insertions, 218 deletions
diff --git a/src/com/android/gallery3d/ingest/IngestActivity.java b/src/com/android/gallery3d/ingest/IngestActivity.java
index 4e603bed3..893f59572 100644
--- a/src/com/android/gallery3d/ingest/IngestActivity.java
+++ b/src/com/android/gallery3d/ingest/IngestActivity.java
@@ -22,11 +22,14 @@ import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.content.res.Configuration;
+import android.database.DataSetObserver;
import android.mtp.MtpObjectInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.support.v4.view.ViewPager;
import android.util.SparseBooleanArray;
import android.view.ActionMode;
import android.view.Menu;
@@ -36,12 +39,16 @@ import android.view.View;
import android.widget.AbsListView.MultiChoiceModeListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
-import android.widget.GridView;
import android.widget.TextView;
import com.android.gallery3d.R;
+import com.android.gallery3d.ingest.adapter.CheckBroker;
import com.android.gallery3d.ingest.adapter.MtpAdapter;
+import com.android.gallery3d.ingest.adapter.MtpPagerAdapter;
+import com.android.gallery3d.ingest.data.MtpBitmapFetch;
import com.android.gallery3d.ingest.ui.DateTileView;
+import com.android.gallery3d.ingest.ui.IngestGridView;
+import com.android.gallery3d.ingest.ui.IngestGridView.OnClearChoicesListener;
import java.lang.ref.WeakReference;
import java.util.Collection;
@@ -51,14 +58,22 @@ public class IngestActivity extends Activity implements
private IngestService mHelperService;
private boolean mActive = false;
- private GridView mGridView;
+ private IngestGridView mGridView;
private MtpAdapter mAdapter;
private Handler mHandler;
private ProgressDialog mProgressDialog;
private ActionMode mActiveActionMode;
- private View mWarningOverlay;
- private TextView mWarningOverlayText;
+ private View mWarningView;
+ private TextView mWarningText;
+ private int mLastCheckedPosition = 0;
+
+ private ViewPager mFullscreenPager;
+ private MtpPagerAdapter mPagerAdapter;
+ private boolean mFullscreenPagerVisible = false;
+
+ private MenuItem mMenuSwitcherItem;
+ private MenuItem mActionMenuSwitcherItem;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -66,18 +81,25 @@ public class IngestActivity extends Activity implements
doBindHelperService();
setContentView(R.layout.ingest_activity_item_list);
- mGridView = (GridView) findViewById(R.id.ingest_gridview);
+ mGridView = (IngestGridView) findViewById(R.id.ingest_gridview);
mAdapter = new MtpAdapter(this);
+ mAdapter.registerDataSetObserver(mMasterObserver);
mGridView.setAdapter(mAdapter);
mGridView.setMultiChoiceModeListener(mMultiChoiceModeListener);
mGridView.setOnItemClickListener(mOnItemClickListener);
+ mGridView.setOnClearChoicesListener(mPositionMappingCheckBroker);
+
+ mFullscreenPager = (ViewPager) findViewById(R.id.ingest_view_pager);
mHandler = new ItemListHandler(this);
+
+ MtpBitmapFetch.configureForContext(this);
}
private OnItemClickListener mOnItemClickListener = new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View itemView, int position, long arg3) {
+ mLastCheckedPosition = position;
mGridView.setItemChecked(position, !mGridView.getCheckedItemPositions().get(position));
}
};
@@ -124,23 +146,18 @@ public class IngestActivity extends Activity implements
mGridView.setItemChecked(i, rangeValue);
}
+ mPositionMappingCheckBroker.onBulkCheckedChange();
mIgnoreItemCheckedStateChanges = false;
+ } else {
+ mPositionMappingCheckBroker.onCheckedChange(position, checked);
}
+ mLastCheckedPosition = position;
updateSelectedTitle(mode);
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
- switch (item.getItemId()) {
- case R.id.import_items:
- mHelperService.importSelectedItems(
- mGridView.getCheckedItemPositions(),
- mAdapter);
- mode.finish();
- return true;
- default:
- return false;
- }
+ return onOptionsItemSelected(item);
}
@Override
@@ -149,12 +166,16 @@ public class IngestActivity extends Activity implements
inflater.inflate(R.menu.ingest_menu_item_list_selection, menu);
updateSelectedTitle(mode);
mActiveActionMode = mode;
+ mActionMenuSwitcherItem = menu.findItem(R.id.ingest_switch_view);
+ setSwitcherMenuState(mActionMenuSwitcherItem, mFullscreenPagerVisible);
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
mActiveActionMode = null;
+ mActionMenuSwitcherItem = null;
+ mHandler.sendEmptyMessage(ItemListHandler.MSG_BULK_CHECKED_CHANGE);
}
@Override
@@ -164,6 +185,34 @@ public class IngestActivity extends Activity implements
}
};
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case R.id.import_items:
+ if (mActiveActionMode != null) {
+ mHelperService.importSelectedItems(
+ mGridView.getCheckedItemPositions(),
+ mAdapter);
+ mActiveActionMode.finish();
+ }
+ return true;
+ case R.id.ingest_switch_view:
+ setFullscreenPagerVisibility(!mFullscreenPagerVisible);
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuInflater inflater = getMenuInflater();
+ inflater.inflate(R.menu.ingest_menu_item_list_selection, menu);
+ mMenuSwitcherItem = menu.findItem(R.id.ingest_switch_view);
+ menu.findItem(R.id.import_items).setVisible(false);
+ setSwitcherMenuState(mMenuSwitcherItem, mFullscreenPagerVisible);
+ return true;
+ }
+
@Override
protected void onDestroy() {
super.onDestroy();
@@ -175,7 +224,7 @@ public class IngestActivity extends Activity implements
DateTileView.refreshLocale();
mActive = true;
if (mHelperService != null) mHelperService.setClientActivity(this);
- updateWarningOverlay();
+ updateWarningView();
super.onResume();
}
@@ -187,31 +236,140 @@ public class IngestActivity extends Activity implements
super.onPause();
}
- private void showWarningOverlay(int textResId) {
- if (mWarningOverlay == null) {
- mWarningOverlay = findViewById(R.id.ingest_warning_overlay);
- mWarningOverlayText =
- (TextView)mWarningOverlay.findViewById(R.id.ingest_warning_overlay_text);
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ MtpBitmapFetch.configureForContext(this);
+ }
+
+ private void showWarningView(int textResId) {
+ if (mWarningView == null) {
+ mWarningView = findViewById(R.id.ingest_warning_view);
+ mWarningText =
+ (TextView)mWarningView.findViewById(R.id.ingest_warning_view_text);
}
- mWarningOverlayText.setText(textResId);
- mWarningOverlay.setVisibility(View.VISIBLE);
+ mWarningText.setText(textResId);
+ mWarningView.setVisibility(View.VISIBLE);
+ setFullscreenPagerVisibility(false);
mGridView.setVisibility(View.GONE);
}
- private void hideWarningOverlay() {
- if (mWarningOverlay != null) {
- mWarningOverlay.setVisibility(View.GONE);
- mGridView.setVisibility(View.VISIBLE);
+ private void hideWarningView() {
+ if (mWarningView != null) {
+ mWarningView.setVisibility(View.GONE);
+ setFullscreenPagerVisibility(false);
}
}
- private void updateWarningOverlay() {
+ private PositionMappingCheckBroker mPositionMappingCheckBroker = new PositionMappingCheckBroker();
+
+ private class PositionMappingCheckBroker extends CheckBroker
+ implements OnClearChoicesListener {
+ private int mLastMappingPager = -1;
+ private int mLastMappingGrid = -1;
+
+ private int mapPagerToGridPosition(int position) {
+ if (position != mLastMappingPager) {
+ mLastMappingPager = position;
+ mLastMappingGrid = mAdapter.translatePositionWithoutLabels(position);
+ }
+ return mLastMappingGrid;
+ }
+
+ private int mapGridToPagerPosition(int position) {
+ if (position != mLastMappingGrid) {
+ mLastMappingGrid = position;
+ mLastMappingPager = mPagerAdapter.translatePositionWithLabels(position);
+ }
+ return mLastMappingPager;
+ }
+
+ @Override
+ public void setItemChecked(int position, boolean checked) {
+ mGridView.setItemChecked(mapPagerToGridPosition(position), checked);
+ }
+
+ @Override
+ public void onCheckedChange(int position, boolean checked) {
+ if (mPagerAdapter != null) {
+ super.onCheckedChange(mapGridToPagerPosition(position), checked);
+ }
+ }
+
+ @Override
+ public boolean isItemChecked(int position) {
+ return mGridView.getCheckedItemPositions().get(mapPagerToGridPosition(position));
+ }
+
+ @Override
+ public void onClearChoices() {
+ onBulkCheckedChange();
+ }
+ };
+
+ private DataSetObserver mMasterObserver = new DataSetObserver() {
+ @Override
+ public void onChanged() {
+ if (mPagerAdapter != null) mPagerAdapter.notifyDataSetChanged();
+ }
+
+ @Override
+ public void onInvalidated() {
+ if (mPagerAdapter != null) mPagerAdapter.notifyDataSetChanged();
+ }
+ };
+
+ private int pickFullscreenStartingPosition() {
+ int firstVisiblePosition = mGridView.getFirstVisiblePosition();
+ if (mLastCheckedPosition <= firstVisiblePosition
+ || mLastCheckedPosition > mGridView.getLastVisiblePosition()) {
+ return firstVisiblePosition;
+ } else {
+ return mLastCheckedPosition;
+ }
+ }
+
+ private void setSwitcherMenuState(MenuItem menuItem, boolean inFullscreenMode) {
+ if (menuItem == null) return;
+ if (!inFullscreenMode) {
+ menuItem.setIcon(android.R.drawable.ic_menu_zoom);
+ menuItem.setTitle(R.string.switch_photo_fullscreen);
+ } else {
+ menuItem.setIcon(android.R.drawable.ic_dialog_dialer);
+ menuItem.setTitle(R.string.switch_photo_grid);
+ }
+ }
+
+ private void setFullscreenPagerVisibility(boolean visible) {
+ mFullscreenPagerVisible = visible;
+ if (visible) {
+ if (mPagerAdapter == null) {
+ mPagerAdapter = new MtpPagerAdapter(this, mPositionMappingCheckBroker);
+ mPagerAdapter.setMtpDeviceIndex(mAdapter.getMtpDeviceIndex());
+ }
+ mFullscreenPager.setAdapter(mPagerAdapter);
+ mFullscreenPager.setCurrentItem(mPagerAdapter.translatePositionWithLabels(
+ pickFullscreenStartingPosition()), false);
+ } else if (mPagerAdapter != null) {
+ mGridView.setSelection(mAdapter.translatePositionWithoutLabels(
+ mFullscreenPager.getCurrentItem()));
+ mFullscreenPager.setAdapter(null);
+ }
+ mGridView.setVisibility(visible ? View.INVISIBLE : View.VISIBLE);
+ mFullscreenPager.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
+ if (mActionMenuSwitcherItem != null) {
+ setSwitcherMenuState(mActionMenuSwitcherItem, visible);
+ }
+ setSwitcherMenuState(mMenuSwitcherItem, visible);
+ }
+
+ private void updateWarningView() {
if (!mAdapter.deviceConnected()) {
- showWarningOverlay(R.string.ingest_no_device);
+ showWarningView(R.string.ingest_no_device);
} else if (mAdapter.indexReady() && mAdapter.getCount() == 0) {
- showWarningOverlay(R.string.ingest_empty_device);
+ showWarningView(R.string.ingest_empty_device);
} else {
- hideWarningOverlay();
+ hideWarningView();
}
}
@@ -221,7 +379,7 @@ public class IngestActivity extends Activity implements
mActiveActionMode.finish();
mActiveActionMode = null;
}
- updateWarningOverlay();
+ updateWarningView();
}
protected void notifyIndexChanged() {
@@ -330,6 +488,7 @@ public class IngestActivity extends Activity implements
public static final int MSG_PROGRESS_UPDATE = 0;
public static final int MSG_PROGRESS_HIDE = 1;
public static final int MSG_NOTIFY_CHANGED = 2;
+ public static final int MSG_BULK_CHECKED_CHANGE = 3;
WeakReference<IngestActivity> mParentReference;
@@ -352,6 +511,9 @@ public class IngestActivity extends Activity implements
case MSG_NOTIFY_CHANGED:
parent.UiThreadNotifyIndexChanged();
break;
+ case MSG_BULK_CHECKED_CHANGE:
+ parent.mPositionMappingCheckBroker.onBulkCheckedChange();
+ break;
default:
break;
}
@@ -362,7 +524,9 @@ public class IngestActivity extends Activity implements
public void onServiceConnected(ComponentName className, IBinder service) {
mHelperService = ((IngestService.LocalBinder) service).getService();
mHelperService.setClientActivity(IngestActivity.this);
- mAdapter.setMtpDeviceIndex(mHelperService.getIndex());
+ MtpDeviceIndex index = mHelperService.getIndex();
+ mAdapter.setMtpDeviceIndex(index);
+ if (mPagerAdapter != null) mPagerAdapter.setMtpDeviceIndex(index);
}
public void onServiceDisconnected(ComponentName className) {
diff --git a/src/com/android/gallery3d/ingest/IngestService.java b/src/com/android/gallery3d/ingest/IngestService.java
index 12b056b60..5e0ca0b68 100644
--- a/src/com/android/gallery3d/ingest/IngestService.java
+++ b/src/com/android/gallery3d/ingest/IngestService.java
@@ -37,7 +37,7 @@ import android.widget.Adapter;
import com.android.gallery3d.R;
import com.android.gallery3d.app.NotificationIds;
import com.android.gallery3d.data.MtpClient;
-import com.android.gallery3d.ingest.ui.MtpBitmapCache;
+import com.android.gallery3d.ingest.data.MtpBitmapFetch;
import com.android.gallery3d.util.BucketNames;
import java.util.ArrayList;
@@ -66,6 +66,7 @@ public class IngestService extends Service implements ImportTask.Listener,
private boolean mRedeliverImportFinish = false;
private Collection<MtpObjectInfo> mRedeliverObjectsNotImported;
private boolean mRedeliverNotifyIndexChanged = false;
+ private boolean mRedeliverIndexFinish = false;
private NotificationManager mNotificationManager;
private NotificationCompat.Builder mNotificationBuilder;
private long mLastProgressIndexTime = 0;
@@ -108,13 +109,19 @@ public class IngestService extends Service implements ImportTask.Listener,
mRedeliverImportFinish = false;
mRedeliverObjectsNotImported = null;
mRedeliverNotifyIndexChanged = false;
+ mRedeliverIndexFinish = false;
mDevice = device;
mIndex.setDevice(mDevice);
if (mDevice != null) {
MtpDeviceInfo deviceInfo = mDevice.getDeviceInfo();
- mDevicePrettyName = deviceInfo.getModel();
- mNotificationBuilder.setContentTitle(mDevicePrettyName);
- new Thread(mIndex.getIndexRunnable()).start();
+ if (deviceInfo == null) {
+ setDevice(null);
+ return;
+ } else {
+ mDevicePrettyName = deviceInfo.getModel();
+ mNotificationBuilder.setContentTitle(mDevicePrettyName);
+ new Thread(mIndex.getIndexRunnable()).start();
+ }
} else {
mDevicePrettyName = null;
}
@@ -144,6 +151,10 @@ public class IngestService extends Service implements ImportTask.Listener,
mClientActivity.notifyIndexChanged();
mRedeliverNotifyIndexChanged = false;
}
+ if (mRedeliverIndexFinish) {
+ mClientActivity.onIndexFinish();
+ mRedeliverIndexFinish = false;
+ }
}
protected void importSelectedItems(SparseBooleanArray selected, Adapter adapter) {
@@ -176,8 +187,8 @@ public class IngestService extends Service implements ImportTask.Listener,
public void deviceRemoved(MtpDevice device) {
if (device == mDevice) {
setDevice(null);
+ MtpBitmapFetch.onDeviceDisconnected(device);
}
- MtpBitmapCache.onDeviceDisconnected(device);
}
@Override
@@ -197,6 +208,7 @@ public class IngestService extends Service implements ImportTask.Listener,
@Override
public void onImportFinish(Collection<MtpObjectInfo> objectsNotImported) {
+ stopForeground(true);
if (mClientActivity != null) {
mClientActivity.onImportFinish(objectsNotImported);
} else {
@@ -207,7 +219,6 @@ public class IngestService extends Service implements ImportTask.Listener,
mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_IMPORTING,
mNotificationBuilder.build());
}
- stopForeground(mClientActivity != null);
}
@Override
@@ -241,6 +252,7 @@ public class IngestService extends Service implements ImportTask.Listener,
.setContentText(getResources().getText(R.string.ingest_scanning_done));
mNotificationManager.notify(NotificationIds.INGEST_NOTIFICATION_SCANNING,
mNotificationBuilder.build());
+ mRedeliverIndexFinish = true;
}
}
diff --git a/src/com/android/gallery3d/ingest/MtpDeviceIndex.java b/src/com/android/gallery3d/ingest/MtpDeviceIndex.java
index 28e115ab0..e873dd1ca 100644
--- a/src/com/android/gallery3d/ingest/MtpDeviceIndex.java
+++ b/src/com/android/gallery3d/ingest/MtpDeviceIndex.java
@@ -180,55 +180,90 @@ public class MtpDeviceIndex {
* order
*/
public Object get(int position, SortOrder order) {
+ if (mProgress != Progress.Finished) return null;
if(order == SortOrder.Ascending) {
- return getAscending(position);
+ DateBucket bucket = mBuckets[mUnifiedLookupIndex[position]];
+ if (bucket.unifiedStartIndex == position) {
+ return bucket.bucket;
+ } else {
+ return mMtpObjects[bucket.itemsStartIndex + position - 1
+ - bucket.unifiedStartIndex];
+ }
} else {
- return getDescending(position);
+ int zeroIndex = mUnifiedLookupIndex.length - 1 - position;
+ DateBucket bucket = mBuckets[mUnifiedLookupIndex[zeroIndex]];
+ if (bucket.unifiedEndIndex == zeroIndex) {
+ return bucket.bucket;
+ } else {
+ return mMtpObjects[bucket.itemsStartIndex + zeroIndex
+ - bucket.unifiedStartIndex];
+ }
}
}
/**
- * @param position Index of item to fetch, where 0 is the first item in
- * ascending order
- * @return position-th item in ascending order
+ * @param position Index of item to fetch from a view of the data that doesn't
+ * include labels and is in the specified order
+ * @return position-th item in specified order, when not including labels
*/
- public Object getAscending(int position) {
+ public MtpObjectInfo getWithoutLabels(int position, SortOrder order) {
if (mProgress != Progress.Finished) return null;
- DateBucket bucket = mBuckets[mUnifiedLookupIndex[position]];
- if (bucket.unifiedStartIndex == position) {
- return bucket.bucket;
+ if (order == SortOrder.Ascending) {
+ return mMtpObjects[position];
} else {
- return bucket.get(position - 1 - bucket.unifiedStartIndex);
+ return mMtpObjects[mMtpObjects.length - 1 - position];
}
}
/**
- * @param position Index of item to fetch, where 0 is the last item in
- * ascending order
- * @return position-th item in descending order
+ * Although this is O(log(number of buckets)), and thus should not be used
+ * in hotspots, even if the attached device has items for every day for
+ * a five-year timeframe, it would still only take 11 iterations at most,
+ * so shouldn't be a huge issue.
+ * @param position Index of item to map from a view of the data that doesn't
+ * include labels and is in the specified order
+ * @param order
+ * @return position in a view of the data that does include labels
*/
- public Object getDescending(int position) {
- if (mProgress != Progress.Finished) return null;
- int zeroIndex = mUnifiedLookupIndex.length - 1 - position;
- DateBucket bucket = mBuckets[mUnifiedLookupIndex[zeroIndex]];
- if (bucket.unifiedEndIndex == zeroIndex) {
- return bucket.bucket;
- } else {
- return bucket.get(zeroIndex - bucket.unifiedStartIndex);
+ public int getPositionFromPositionWithoutLabels(int position, SortOrder order) {
+ if (mProgress != Progress.Finished) return -1;
+ if (order == SortOrder.Descending) {
+ position = mMtpObjects.length - 1 - position;
+ }
+ int bucketNumber = 0;
+ int iMin = 0;
+ int iMax = mBuckets.length - 1;
+ while (iMax >= iMin) {
+ int iMid = (iMax + iMin) / 2;
+ if (mBuckets[iMid].itemsStartIndex + mBuckets[iMid].numItems <= position) {
+ iMin = iMid + 1;
+ } else if (mBuckets[iMid].itemsStartIndex > position) {
+ iMax = iMid - 1;
+ } else {
+ bucketNumber = iMid;
+ break;
+ }
}
+ int mappedPos = mBuckets[bucketNumber].unifiedStartIndex
+ + position - mBuckets[bucketNumber].itemsStartIndex;
+ if (order == SortOrder.Descending) {
+ mappedPos = mUnifiedLookupIndex.length - 1 - mappedPos;
+ }
+ return mappedPos;
}
- /**
- * @param position Index of item to fetch from a view of the data that doesn't
- * include labels and is in ascending order
- * @return position-th item in ascending order, when not including labels
- */
- public MtpObjectInfo getWithoutLabels(int position, SortOrder order) {
- if (mProgress != Progress.Finished) return null;
- if (order == SortOrder.Ascending) {
- return mMtpObjects[position];
+ public int getPositionWithoutLabelsFromPosition(int position, SortOrder order) {
+ if (mProgress != Progress.Finished) return -1;
+ if(order == SortOrder.Ascending) {
+ DateBucket bucket = mBuckets[mUnifiedLookupIndex[position]];
+ if (bucket.unifiedStartIndex == position) position++;
+ return bucket.itemsStartIndex + position - 1 - bucket.unifiedStartIndex;
} else {
- return mMtpObjects[mMtpObjects.length - 1 - position];
+ int zeroIndex = mUnifiedLookupIndex.length - 1 - position;
+ DateBucket bucket = mBuckets[mUnifiedLookupIndex[zeroIndex]];
+ if (bucket.unifiedEndIndex == zeroIndex) zeroIndex--;
+ return mMtpObjects.length - 1 - bucket.itemsStartIndex
+ - zeroIndex + bucket.unifiedStartIndex;
}
}
@@ -288,6 +323,7 @@ public class MtpDeviceIndex {
int unifiedStartIndex;
int unifiedEndIndex;
int itemsStartIndex;
+ int numItems;
public DateBucket(SimpleDate bucket) {
this.bucket = bucket;
@@ -302,10 +338,6 @@ public class MtpDeviceIndex {
Collections.sort(tempElementsList, comparator);
}
- public MtpObjectInfo get(int position) {
- return mMtpObjects[itemsStartIndex + position];
- }
-
@Override
public String toString() {
return bucket.toString();
@@ -413,7 +445,8 @@ public class MtpDeviceIndex {
currentUnifiedIndexEntry = nextUnifiedEntry;
bucket.itemsStartIndex = currentItemsEntry;
- for (int j = 0; j < bucket.tempElementsList.size(); j++) {
+ bucket.numItems = bucket.tempElementsList.size();
+ for (int j = 0; j < bucket.numItems; j++) {
mMtpObjects[currentItemsEntry] = bucket.tempElementsList.get(j);
currentItemsEntry++;
}
diff --git a/src/com/android/gallery3d/ingest/adapter/CheckBroker.java b/src/com/android/gallery3d/ingest/adapter/CheckBroker.java
new file mode 100644
index 000000000..6783f23c5
--- /dev/null
+++ b/src/com/android/gallery3d/ingest/adapter/CheckBroker.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.ingest.adapter;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public abstract class CheckBroker {
+ private Collection<OnCheckedChangedListener> mListeners =
+ new ArrayList<OnCheckedChangedListener>();
+
+ public interface OnCheckedChangedListener {
+ public void onCheckedChanged(int position, boolean isChecked);
+ public void onBulkCheckedChanged();
+ }
+
+ public abstract void setItemChecked(int position, boolean checked);
+
+ public void onCheckedChange(int position, boolean checked) {
+ if (isItemChecked(position) != checked) {
+ for (OnCheckedChangedListener l : mListeners) {
+ l.onCheckedChanged(position, checked);
+ }
+ }
+ }
+
+ public void onBulkCheckedChange() {
+ for (OnCheckedChangedListener l : mListeners) {
+ l.onBulkCheckedChanged();
+ }
+ }
+
+ public abstract boolean isItemChecked(int position);
+
+ public void registerOnCheckedChangeListener(OnCheckedChangedListener l) {
+ mListeners.add(l);
+ }
+
+ public void unregisterOnCheckedChangeListener(OnCheckedChangedListener l) {
+ mListeners.remove(l);
+ }
+}
diff --git a/src/com/android/gallery3d/ingest/adapter/MtpAdapter.java b/src/com/android/gallery3d/ingest/adapter/MtpAdapter.java
index 611d880db..e8dd69f8c 100644
--- a/src/com/android/gallery3d/ingest/adapter/MtpAdapter.java
+++ b/src/com/android/gallery3d/ingest/adapter/MtpAdapter.java
@@ -45,8 +45,7 @@ public class MtpAdapter extends BaseAdapter implements SectionIndexer {
public MtpAdapter(Activity context) {
super();
mContext = context;
- mInflater = (LayoutInflater)context.getSystemService
- (Context.LAYOUT_INFLATER_SERVICE);
+ mInflater = LayoutInflater.from(context);
}
public void setMtpDeviceIndex(MtpDeviceIndex index) {
@@ -54,6 +53,10 @@ public class MtpAdapter extends BaseAdapter implements SectionIndexer {
notifyDataSetChanged();
}
+ public MtpDeviceIndex getMtpDeviceIndex() {
+ return mModel;
+ }
+
@Override
public void notifyDataSetChanged() {
mGeneration++;
@@ -177,4 +180,13 @@ public class MtpAdapter extends BaseAdapter implements SectionIndexer {
public Object[] getSections() {
return getCount() > 0 ? mModel.getBuckets(mSortOrder) : null;
}
+
+ public SortOrder getSortOrder() {
+ return mSortOrder;
+ }
+
+ public int translatePositionWithoutLabels(int position) {
+ if (mModel == null) return -1;
+ return mModel.getPositionFromPositionWithoutLabels(position, mSortOrder);
+ }
}
diff --git a/src/com/android/gallery3d/ingest/adapter/MtpPagerAdapter.java b/src/com/android/gallery3d/ingest/adapter/MtpPagerAdapter.java
new file mode 100644
index 000000000..9e7abc01d
--- /dev/null
+++ b/src/com/android/gallery3d/ingest/adapter/MtpPagerAdapter.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.ingest.adapter;
+
+import android.content.Context;
+import android.mtp.MtpObjectInfo;
+import android.support.v4.view.PagerAdapter;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.ingest.MtpDeviceIndex;
+import com.android.gallery3d.ingest.MtpDeviceIndex.SortOrder;
+import com.android.gallery3d.ingest.ui.MtpFullscreenView;
+
+public class MtpPagerAdapter extends PagerAdapter {
+
+ private LayoutInflater mInflater;
+ private int mGeneration = 0;
+ private CheckBroker mBroker;
+ private MtpDeviceIndex mModel;
+ private SortOrder mSortOrder = SortOrder.Descending;
+
+ private MtpFullscreenView mReusableView = null;
+
+ public MtpPagerAdapter(Context context, CheckBroker broker) {
+ super();
+ mInflater = LayoutInflater.from(context);
+ mBroker = broker;
+ }
+
+ public void setMtpDeviceIndex(MtpDeviceIndex index) {
+ mModel = index;
+ notifyDataSetChanged();
+ }
+
+ @Override
+ public int getCount() {
+ return mModel != null ? mModel.sizeWithoutLabels() : 0;
+ }
+
+ @Override
+ public void notifyDataSetChanged() {
+ mGeneration++;
+ super.notifyDataSetChanged();
+ }
+
+ public int translatePositionWithLabels(int position) {
+ if (mModel == null) return -1;
+ return mModel.getPositionWithoutLabelsFromPosition(position, mSortOrder);
+ }
+
+ @Override
+ public void finishUpdate(ViewGroup container) {
+ mReusableView = null;
+ super.finishUpdate(container);
+ }
+
+ @Override
+ public boolean isViewFromObject(View view, Object object) {
+ return view == object;
+ }
+
+ @Override
+ public void destroyItem(ViewGroup container, int position, Object object) {
+ MtpFullscreenView v = (MtpFullscreenView)object;
+ container.removeView(v);
+ mBroker.unregisterOnCheckedChangeListener(v);
+ mReusableView = v;
+ }
+
+ @Override
+ public Object instantiateItem(ViewGroup container, int position) {
+ MtpFullscreenView v;
+ if (mReusableView != null) {
+ v = mReusableView;
+ mReusableView = null;
+ } else {
+ v = (MtpFullscreenView) mInflater.inflate(R.layout.ingest_fullsize, container, false);
+ }
+ MtpObjectInfo i = mModel.getWithoutLabels(position, mSortOrder);
+ v.getImageView().setMtpDeviceAndObjectInfo(mModel.getDevice(), i, mGeneration);
+ v.setPositionAndBroker(position, mBroker);
+ container.addView(v);
+ return v;
+ }
+}
diff --git a/src/com/android/gallery3d/ingest/data/BitmapWithMetadata.java b/src/com/android/gallery3d/ingest/data/BitmapWithMetadata.java
new file mode 100644
index 000000000..bbc90f670
--- /dev/null
+++ b/src/com/android/gallery3d/ingest/data/BitmapWithMetadata.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.ingest.data;
+
+import android.graphics.Bitmap;
+
+public class BitmapWithMetadata {
+ public Bitmap bitmap;
+ public int rotationDegrees;
+
+ public BitmapWithMetadata(Bitmap bitmap, int rotationDegrees) {
+ this.bitmap = bitmap;
+ this.rotationDegrees = rotationDegrees;
+ }
+}
diff --git a/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java b/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java
new file mode 100644
index 000000000..88645e8d0
--- /dev/null
+++ b/src/com/android/gallery3d/ingest/data/MtpBitmapFetch.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.ingest.data;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.mtp.MtpDevice;
+import android.mtp.MtpObjectInfo;
+import android.util.DisplayMetrics;
+import android.view.WindowManager;
+
+import com.android.camera.Exif;
+import com.android.gallery3d.common.Utils;
+import com.android.gallery3d.data.BitmapPool;
+
+import java.util.ArrayList;
+
+public class MtpBitmapFetch {
+ private static final int BITMAP_POOL_SIZE = 32;
+ private static BitmapPool sThumbnailPool = new BitmapPool(BITMAP_POOL_SIZE);
+ private static int sMaxSize = 0;
+
+ public static void recycleThumbnail(Bitmap b) {
+ if (b != null) {
+ sThumbnailPool.recycle(b);
+ }
+ }
+
+ public static Bitmap getThumbnail(MtpDevice device, MtpObjectInfo info) {
+ byte[] imageBytes = device.getThumbnail(info.getObjectHandle());
+ BitmapFactory.Options o = new BitmapFactory.Options();
+ o.inJustDecodeBounds = true;
+ BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o);
+ if (o.outWidth == 0 || o.outHeight == 0) return null;
+ o.inBitmap = sThumbnailPool.getBitmap(o.outWidth, o.outHeight);
+ o.inMutable = true;
+ o.inJustDecodeBounds = false;
+ o.inSampleSize = 1;
+ return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o);
+ }
+
+ public static BitmapWithMetadata getFullsize(MtpDevice device, MtpObjectInfo info) {
+ return getFullsize(device, info, sMaxSize);
+ }
+
+ public static BitmapWithMetadata getFullsize(MtpDevice device, MtpObjectInfo info, int maxSide) {
+ byte[] imageBytes = device.getObject(info.getObjectHandle(), info.getCompressedSize());
+ Bitmap created;
+ if (maxSide > 0) {
+ BitmapFactory.Options o = new BitmapFactory.Options();
+ o.inJustDecodeBounds = true;
+ BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o);
+ int w = o.outWidth;
+ int h = o.outHeight;
+ int comp = Math.max(h, w);
+ int sampleSize = 1;
+ while ((comp >> 1) >= maxSide) {
+ comp = comp >> 1;
+ sampleSize++;
+ }
+ o.inSampleSize = sampleSize;
+ o.inJustDecodeBounds = false;
+ created = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length, o);
+ } else {
+ created = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
+ }
+ if (created == null) return null;
+
+ return new BitmapWithMetadata(created, Exif.getOrientation(imageBytes));
+ }
+
+ public static void onDeviceDisconnected(MtpDevice device) {
+ sThumbnailPool.clear();
+ }
+
+ public static void configureForContext(Context context) {
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager wm = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
+ wm.getDefaultDisplay().getMetrics(metrics);
+ sMaxSize = Math.max(metrics.heightPixels, metrics.widthPixels);
+ }
+}
diff --git a/src/com/android/gallery3d/ingest/ui/IngestGridView.java b/src/com/android/gallery3d/ingest/ui/IngestGridView.java
new file mode 100644
index 000000000..c821259fe
--- /dev/null
+++ b/src/com/android/gallery3d/ingest/ui/IngestGridView.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.ingest.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.GridView;
+
+/**
+ * This just extends GridView with the ability to listen for calls
+ * to clearChoices()
+ */
+public class IngestGridView extends GridView {
+
+ public interface OnClearChoicesListener {
+ public void onClearChoices();
+ }
+
+ private OnClearChoicesListener mOnClearChoicesListener = null;
+
+ public IngestGridView(Context context) {
+ super(context);
+ }
+
+ public IngestGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public IngestGridView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public void setOnClearChoicesListener(OnClearChoicesListener l) {
+ mOnClearChoicesListener = l;
+ }
+
+ @Override
+ public void clearChoices() {
+ super.clearChoices();
+ if (mOnClearChoicesListener != null) {
+ mOnClearChoicesListener.onClearChoices();
+ }
+ }
+}
diff --git a/src/com/android/gallery3d/ingest/ui/MtpBitmapCache.java b/src/com/android/gallery3d/ingest/ui/MtpBitmapCache.java
deleted file mode 100644
index 307531d5b..000000000
--- a/src/com/android/gallery3d/ingest/ui/MtpBitmapCache.java
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.gallery3d.ingest.ui;
-
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.mtp.MtpDevice;
-import android.util.LruCache;
-
-public class MtpBitmapCache extends LruCache<Integer, Bitmap> {
- private static final int PER_DEVICE_CACHE_MAX_BYTES = 4194304;
- private static MtpBitmapCache sInstance;
-
- public synchronized static MtpBitmapCache getInstanceForDevice(MtpDevice device) {
- if (sInstance == null || sInstance.mDevice != device) {
- sInstance = new MtpBitmapCache(PER_DEVICE_CACHE_MAX_BYTES, device);
- }
- return sInstance;
- }
-
- public synchronized static void onDeviceDisconnected(MtpDevice device) {
- if (sInstance != null && sInstance.mDevice == device) {
- synchronized (sInstance) {
- sInstance.mDevice = null;
- }
- sInstance = null;
- }
- }
-
- private MtpDevice mDevice;
-
- private MtpBitmapCache(int maxSize, MtpDevice device) {
- super(maxSize);
- mDevice = device;
- }
-
- @Override
- protected int sizeOf(Integer key, Bitmap value) {
- return value.getByteCount();
- }
-
- public Bitmap getOrCreate(Integer key) {
- Bitmap b = get(key);
- return b == null ? createAndInsert(key) : b;
- }
-
- private Bitmap createAndInsert(Integer key) {
- MtpDevice device;
- synchronized (this) {
- device = mDevice;
- }
- if (device == null) return null;
- byte[] imageBytes = device.getThumbnail(key);
- if (imageBytes == null) return null;
- Bitmap created = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
- put(key, created);
- return created;
- }
-}
diff --git a/src/com/android/gallery3d/ingest/ui/MtpFullscreenView.java b/src/com/android/gallery3d/ingest/ui/MtpFullscreenView.java
new file mode 100644
index 000000000..8d3884dc6
--- /dev/null
+++ b/src/com/android/gallery3d/ingest/ui/MtpFullscreenView.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.ingest.ui;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.CheckBox;
+import android.widget.Checkable;
+import android.widget.CompoundButton;
+import android.widget.CompoundButton.OnCheckedChangeListener;
+import android.widget.RelativeLayout;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.ingest.adapter.CheckBroker;
+
+public class MtpFullscreenView extends RelativeLayout implements Checkable,
+ CompoundButton.OnCheckedChangeListener, CheckBroker.OnCheckedChangedListener {
+
+ private MtpImageView mImageView;
+ private CheckBox mCheckbox;
+ private int mPosition = -1;
+ private CheckBroker mBroker;
+
+ public MtpFullscreenView(Context context) {
+ super(context);
+ }
+
+ public MtpFullscreenView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MtpFullscreenView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mImageView = (MtpImageView) findViewById(R.id.ingest_fullsize_image);
+ mCheckbox = (CheckBox) findViewById(R.id.ingest_fullsize_image_checkbox);
+ mCheckbox.setOnCheckedChangeListener(this);
+ }
+
+ @Override
+ public boolean isChecked() {
+ return mCheckbox.isChecked();
+ }
+
+ @Override
+ public void setChecked(boolean checked) {
+ mCheckbox.setChecked(checked);
+ }
+
+ @Override
+ public void toggle() {
+ mCheckbox.toggle();
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ setPositionAndBroker(-1, null);
+ super.onDetachedFromWindow();
+ }
+
+ public MtpImageView getImageView() {
+ return mImageView;
+ }
+
+ public int getPosition() {
+ return mPosition;
+ }
+
+ public void setPositionAndBroker(int position, CheckBroker b) {
+ if (mBroker != null) {
+ mBroker.unregisterOnCheckedChangeListener(this);
+ }
+ mPosition = position;
+ mBroker = b;
+ if (mBroker != null) {
+ setChecked(mBroker.isItemChecked(position));
+ mBroker.registerOnCheckedChangeListener(this);
+ }
+ }
+
+ @Override
+ public void onCheckedChanged(CompoundButton arg0, boolean isChecked) {
+ if (mBroker != null) mBroker.setItemChecked(mPosition, isChecked);
+ }
+
+ @Override
+ public void onCheckedChanged(int position, boolean isChecked) {
+ if (position == mPosition) {
+ setChecked(isChecked);
+ }
+ }
+
+ @Override
+ public void onBulkCheckedChanged() {
+ if(mBroker != null) setChecked(mBroker.isItemChecked(mPosition));
+ }
+}
diff --git a/src/com/android/gallery3d/ingest/ui/MtpImageView.java b/src/com/android/gallery3d/ingest/ui/MtpImageView.java
new file mode 100644
index 000000000..9c197851e
--- /dev/null
+++ b/src/com/android/gallery3d/ingest/ui/MtpImageView.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.ingest.ui;
+
+import android.content.Context;
+import android.mtp.MtpDevice;
+import android.mtp.MtpObjectInfo;
+import android.os.AsyncTask;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+import com.android.gallery3d.ingest.data.BitmapWithMetadata;
+import com.android.gallery3d.ingest.data.MtpBitmapFetch;
+
+public class MtpImageView extends ImageView {
+ private static final int FADE_IN_TIME_MS = 80;
+
+ private int mObjectHandle;
+ private int mGeneration;
+
+ private void init() {
+ showPlaceholder();
+ }
+
+ public MtpImageView(Context context) {
+ super(context);
+ init();
+ }
+
+ public MtpImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public MtpImageView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init();
+ }
+
+ private void showPlaceholder() {
+ setImageResource(android.R.color.transparent);
+ }
+
+ private LoadMtpImageTask mTask;
+
+ public void setMtpDeviceAndObjectInfo(MtpDevice device, MtpObjectInfo object, int gen) {
+ int handle = object.getObjectHandle();
+ if (handle == mObjectHandle && gen == mGeneration) {
+ return;
+ }
+ cancelLoadingAndClear();
+ showPlaceholder();
+ mGeneration = gen;
+ mObjectHandle = handle;
+ mTask = new LoadMtpImageTask(device);
+ mTask.execute(object);
+ }
+
+ protected Object fetchMtpImageDataFromDevice(MtpDevice device, MtpObjectInfo info) {
+ return MtpBitmapFetch.getFullsize(device, info);
+ }
+
+ protected void onMtpImageDataFetchedFromDevice(Object result) {
+ BitmapWithMetadata bitmapWithMetadata = (BitmapWithMetadata)result;
+ setImageBitmap(bitmapWithMetadata.bitmap);
+ setRotation(bitmapWithMetadata.rotationDegrees);
+ }
+
+ private class LoadMtpImageTask extends AsyncTask<MtpObjectInfo, Void, Object> {
+ private MtpDevice mDevice;
+
+ public LoadMtpImageTask(MtpDevice device) {
+ mDevice = device;
+ }
+
+ @Override
+ protected Object doInBackground(MtpObjectInfo... args) {
+ Object result = null;
+ if (!isCancelled()) {
+ result = fetchMtpImageDataFromDevice(mDevice, args[0]);
+ }
+ mDevice = null;
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(Object result) {
+ if (isCancelled() || result == null) {
+ return;
+ }
+ setAlpha(0f);
+ onMtpImageDataFetchedFromDevice(result);
+ animate().alpha(1f).setDuration(FADE_IN_TIME_MS);
+ }
+
+ @Override
+ protected void onCancelled() {
+ }
+ }
+
+ protected void cancelLoadingAndClear() {
+ if (mTask != null) {
+ mTask.cancel(true);
+ }
+ mTask = null;
+ animate().cancel();
+ setImageResource(android.R.color.transparent);
+ setRotation(0);
+ }
+
+ @Override
+ public void onDetachedFromWindow() {
+ cancelLoadingAndClear();
+ super.onDetachedFromWindow();
+ }
+}
diff --git a/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java b/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java
index 2aeda73db..3307e78aa 100644
--- a/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java
+++ b/src/com/android/gallery3d/ingest/ui/MtpThumbnailTileView.java
@@ -22,26 +22,22 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.mtp.MtpDevice;
import android.mtp.MtpObjectInfo;
-import android.os.AsyncTask;
import android.util.AttributeSet;
-import android.view.View;
import android.widget.Checkable;
-import android.widget.ImageView;
import com.android.gallery3d.R;
+import com.android.gallery3d.ingest.data.MtpBitmapFetch;
-public class MtpThumbnailTileView extends ImageView implements Checkable {
- private static final int FADE_IN_TIME_MS = 80;
+
+public class MtpThumbnailTileView extends MtpImageView implements Checkable {
private Paint mForegroundPaint;
private boolean mIsChecked;
- private int mObjectHandle;
- private int mGeneration;
+ private Bitmap mBitmap;
private void init() {
mForegroundPaint = new Paint();
mForegroundPaint.setColor(getResources().getColor(R.color.ingest_highlight_semitransparent));
- showPlaceholder();
}
public MtpThumbnailTileView(Context context) {
@@ -66,9 +62,20 @@ public class MtpThumbnailTileView extends ImageView implements Checkable {
}
@Override
+ protected Object fetchMtpImageDataFromDevice(MtpDevice device, MtpObjectInfo info) {
+ return MtpBitmapFetch.getThumbnail(device, info);
+ }
+
+ @Override
+ protected void onMtpImageDataFetchedFromDevice(Object result) {
+ mBitmap = (Bitmap)result;
+ setImageBitmap(mBitmap);
+ }
+
+ @Override
public void draw(Canvas canvas) {
super.draw(canvas);
- if (mIsChecked) {
+ if (isChecked()) {
canvas.drawRect(canvas.getClipBounds(), mForegroundPaint);
}
}
@@ -88,65 +95,12 @@ public class MtpThumbnailTileView extends ImageView implements Checkable {
setChecked(!mIsChecked);
}
- private void showPlaceholder() {
- setAlpha(0f);
- }
-
- private LoadThumbnailTask mTask;
-
- public void setMtpDeviceAndObjectInfo(MtpDevice device, MtpObjectInfo object, int gen) {
- int handle = object.getObjectHandle();
- if (handle == mObjectHandle && gen == mGeneration) {
- return;
- }
- animate().cancel();
- if (mTask != null) {
- mTask.cancel(true);
- }
- mGeneration = gen;
- mObjectHandle = handle;
- Bitmap thumbnail = MtpBitmapCache.getInstanceForDevice(device)
- .get(handle);
- if (thumbnail != null) {
- setAlpha(1f);
- setImageBitmap(thumbnail);
- } else {
- showPlaceholder();
- mTask = new LoadThumbnailTask(device);
- mTask.execute(object);
- }
- }
-
- private class LoadThumbnailTask extends AsyncTask<MtpObjectInfo, Void, Bitmap> {
- private MtpDevice mDevice;
-
- public LoadThumbnailTask(MtpDevice device) {
- mDevice = device;
- }
-
- @Override
- protected Bitmap doInBackground(MtpObjectInfo... args) {
- Bitmap result = null;
- if (!isCancelled()) {
- result = MtpBitmapCache.getInstanceForDevice(mDevice).getOrCreate(
- args[0].getObjectHandle());
- }
- mDevice = null;
- return result;
- }
-
- @Override
- protected void onPostExecute(Bitmap result) {
- if (isCancelled() || result == null) {
- return;
- }
- setAlpha(0f);
- setImageBitmap(result);
- animate().alpha(1f).setDuration(FADE_IN_TIME_MS);
- }
-
- @Override
- protected void onCancelled() {
+ @Override
+ protected void cancelLoadingAndClear() {
+ super.cancelLoadingAndClear();
+ if (mBitmap != null) {
+ MtpBitmapFetch.recycleThumbnail(mBitmap);
+ mBitmap = null;
}
}
}