1f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescupackage com.android.gallery3d.ingest.data;
2f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
3f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.annotation.TargetApi;
4f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.mtp.MtpConstants;
5f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.mtp.MtpDevice;
66669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chungimport android.mtp.MtpObjectInfo;
7f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport android.os.Build;
86669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chungimport android.webkit.MimeTypeMap;
9f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
10f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport java.util.Collections;
116669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chungimport java.util.HashMap;
12f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport java.util.HashSet;
136669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chungimport java.util.Locale;
146669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chungimport java.util.Map;
15f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescuimport java.util.Set;
16f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
17f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu/**
18f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * Index of MTP media objects organized into "buckets," or groupings, based on the date
19f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * they were created.
20f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *
21f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * When the index is created, the buckets are sorted in their natural
22f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * order, and the items within the buckets sorted by the date they are taken.
23f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *
24f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * The index enables the access of items and bucket labels as one unified list.
25f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * For example, let's say we have the following data in the index:
26f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *    [Bucket A]: [photo 1], [photo 2]
27f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *    [Bucket B]: [photo 3]
28f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *
29f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * Then the items can be thought of as being organized as a 5 element list:
30f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *   [Bucket A], [photo 1], [photo 2], [Bucket B], [photo 3]
31f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *
32f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * The data can also be accessed in descending order, in which case the list
33f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * would be a bit different from simply reversing the ascending list, since the
34f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * bucket labels need to always be at the beginning:
35f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *   [Bucket B], [photo 3], [Bucket A], [photo 2], [photo 1]
36f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *
37f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * The index enables all the following operations in constant time, both for
38f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * ascending and descending views of the data:
39f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *   - get/getAscending/getDescending: get an item at a specified list position
40f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *   - size: get the total number of items (bucket labels and MTP objects)
41f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *   - getFirstPositionForBucketNumber
42f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *   - getBucketNumberForPosition
43f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *   - isFirstInBucket
44f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu *
45f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu * See {@link MtpDeviceIndexRunnable} for implementation notes.
46f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu */
47f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu@TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1)
48f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescupublic class MtpDeviceIndex {
49f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
50f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
51f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * Indexing progress listener.
52f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
53f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public interface ProgressListener {
54f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    /**
55f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu     * A media item on the device was indexed.
56f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu     * @param object The media item that was just indexed
57f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu     * @param numVisited Number of items visited so far
58f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu     */
59f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onObjectIndexed(IngestObjectInfo object, int numVisited);
60f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
61f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    /**
62f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu     * The metadata loaded from the device is being sorted.
63f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu     */
64f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onSortingStarted();
65f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
66f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    /**
67f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu     * The indexing is done and the index is ready to be used.
68f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu     */
69f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    public void onIndexingFinished();
70f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
71f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
72f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
73f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * Media sort orders.
74f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
75f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public enum SortOrder {
76f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    ASCENDING, DESCENDING
77f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
78f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
79f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /** Quicktime MOV container (not already defined in {@link MtpConstants}) **/
80f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public static final int FORMAT_MOV = 0x300D;
81f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
82f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public static final Set<Integer> SUPPORTED_IMAGE_FORMATS;
83f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public static final Set<Integer> SUPPORTED_VIDEO_FORMATS;
84f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
85f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  static {
86f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    Set<Integer> supportedImageFormats = new HashSet<Integer>();
87f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    supportedImageFormats.add(MtpConstants.FORMAT_JFIF);
88f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    supportedImageFormats.add(MtpConstants.FORMAT_EXIF_JPEG);
89f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    supportedImageFormats.add(MtpConstants.FORMAT_PNG);
90f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    supportedImageFormats.add(MtpConstants.FORMAT_GIF);
91f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    supportedImageFormats.add(MtpConstants.FORMAT_BMP);
926669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    supportedImageFormats.add(MtpConstants.FORMAT_TIFF);
936669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    supportedImageFormats.add(MtpConstants.FORMAT_TIFF_EP);
946669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    if (Build.VERSION.SDK_INT >= 24) {
956669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung      supportedImageFormats.add(MtpConstants.FORMAT_DNG);
966669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    }
97f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    SUPPORTED_IMAGE_FORMATS = Collections.unmodifiableSet(supportedImageFormats);
98f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
99f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    Set<Integer> supportedVideoFormats = new HashSet<Integer>();
100f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    supportedVideoFormats.add(MtpConstants.FORMAT_3GP_CONTAINER);
101f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    supportedVideoFormats.add(MtpConstants.FORMAT_AVI);
102f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    supportedVideoFormats.add(MtpConstants.FORMAT_MP4_CONTAINER);
1036669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    supportedVideoFormats.add(MtpConstants.FORMAT_MP2);
104f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    supportedVideoFormats.add(MtpConstants.FORMAT_MPEG);
105f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    // TODO(georgescu): add FORMAT_MOV once Android Media Scanner supports .mov files
106f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    SUPPORTED_VIDEO_FORMATS = Collections.unmodifiableSet(supportedVideoFormats);
107f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
108f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
109f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private MtpDevice mDevice;
110f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private long mGeneration;
111f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private ProgressListener mProgressListener;
112f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private volatile MtpDeviceIndexRunnable.Results mResults;
113f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private final MtpDeviceIndexRunnable.Factory mIndexRunnableFactory;
114f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
115f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  private static final MtpDeviceIndex sInstance = new MtpDeviceIndex(
116f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      MtpDeviceIndexRunnable.getFactory());
117f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
1186669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung  private static final Map<String, Boolean> sCachedSupportedExtenstions = new HashMap<>();
1196669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung
120f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public static MtpDeviceIndex getInstance() {
121f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return sInstance;
122f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
123f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
124f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected MtpDeviceIndex(MtpDeviceIndexRunnable.Factory indexRunnableFactory) {
125f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mIndexRunnableFactory = indexRunnableFactory;
126f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
127f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
128f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public synchronized MtpDevice getDevice() {
129f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return mDevice;
130f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
131f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
132f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public synchronized boolean isDeviceConnected() {
133f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return (mDevice != null);
134f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
135f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
136f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
1376669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung   * @param mtpObjectInfo MTP object info
138f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return Whether the format is supported by this index.
139f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
1406669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung  public boolean isFormatSupported(MtpObjectInfo mtpObjectInfo) {
1416669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    // Checks whether the format is supported or not.
1426669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    final int format = mtpObjectInfo.getFormat();
1436669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    if (SUPPORTED_IMAGE_FORMATS.contains(format)
1446669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung        || SUPPORTED_VIDEO_FORMATS.contains(format)) {
1456669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung      return true;
1466669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    }
1476669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung
1486669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    // Checks whether the extension is supported or not.
1496669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    final String name = mtpObjectInfo.getName();
1506669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    if (name == null) {
1516669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung      return false;
1526669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    }
1536669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    final int lastDot = name.lastIndexOf('.');
1546669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    if (lastDot >= 0) {
1556669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung      final String extension = name.substring(lastDot + 1);
1566669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung
1576669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung      Boolean result = sCachedSupportedExtenstions.get(extension);
1586669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung      if (result != null) {
1596669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung        return result;
1606669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung      }
1616669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung      final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(
1626669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung          extension.toLowerCase(Locale.US));
1636669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung      if (mime != null) {
1646669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung        // This will also accept the newly added mimetypes for images and videos.
1656669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung        result = mime.startsWith("image/") || mime.startsWith("video/");
1666669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung        sCachedSupportedExtenstions.put(extension, result);
1676669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung        return result;
1686669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung      }
1696669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    }
1706669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung
1716669f2c4e92da4ee45c0d23ebee38a2cf0e7f539Jaesung Chung    return false;
172f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
173f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
174f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
175f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * Sets the MtpDevice that should be indexed and initializes state, but does
176f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * not kick off the actual indexing task, which is instead done by using
177f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * {@link #getIndexRunnable()}
178f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *
179f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param device The MtpDevice that should be indexed
180f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
181f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public synchronized void setDevice(MtpDevice device) {
182f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (device == mDevice) {
183f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return;
184f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
185f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mDevice = device;
186f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    resetState();
187f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
188f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
189f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
190f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * Provides a Runnable for the indexing task (assuming the state has already
191f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * been correctly initialized by calling {@link #setDevice(MtpDevice)}).
192f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *
193f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return Runnable for the main indexing task
194f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
195f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public synchronized Runnable getIndexRunnable() {
196f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (!isDeviceConnected() || mResults != null) {
197f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return null;
198f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
199f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return mIndexRunnableFactory.createMtpDeviceIndexRunnable(this);
200f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
201f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
202f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
203f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return Whether the index is ready to be used.
204f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
205f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public synchronized boolean isIndexReady() {
206f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return mResults != null;
207f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
208f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
209f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
210f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param listener
211f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return Current progress (useful for configuring initial UI state)
212f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
213f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public synchronized void setProgressListener(ProgressListener listener) {
214f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mProgressListener = listener;
215f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
216f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
217f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
218f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * Make the listener null if it matches the argument
219f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *
220f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param listener Listener to unset, if currently registered
221f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
222f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public synchronized void unsetProgressListener(ProgressListener listener) {
223f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mProgressListener == listener) {
224f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mProgressListener = null;
225f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
226f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
227f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
228f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
229f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return The total number of elements in the index (labels and items)
230f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
231f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public int size() {
232f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndexRunnable.Results results = mResults;
233f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return results != null ? results.unifiedLookupIndex.length : 0;
234f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
235f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
236f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
237f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param position Index of item to fetch, where 0 is the first item in the
238f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *            specified order
239f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param order
240f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return the bucket label or IngestObjectInfo at the specified position and
241f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *         order
242f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
243f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public Object get(int position, SortOrder order) {
244f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndexRunnable.Results results = mResults;
245f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (results == null) {
246f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return null;
247f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
248f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (order == SortOrder.ASCENDING) {
249f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      DateBucket bucket = results.buckets[results.unifiedLookupIndex[position]];
250f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (bucket.unifiedStartIndex == position) {
251f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return bucket.date;
252f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      } else {
253f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return results.mtpObjects[bucket.itemsStartIndex + position - 1
254f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu            - bucket.unifiedStartIndex];
255f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
256f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
257f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      int zeroIndex = results.unifiedLookupIndex.length - 1 - position;
258f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      DateBucket bucket = results.buckets[results.unifiedLookupIndex[zeroIndex]];
259f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (bucket.unifiedEndIndex == zeroIndex) {
260f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return bucket.date;
261f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      } else {
262f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        return results.mtpObjects[bucket.itemsStartIndex + zeroIndex
263f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu            - bucket.unifiedStartIndex];
264f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
265f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
266f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
267f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
268f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
269f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param position Index of item to fetch from a view of the data that does not
270f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *            include labels and is in the specified order
271f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return position-th item in specified order, when not including labels
272f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
273f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public IngestObjectInfo getWithoutLabels(int position, SortOrder order) {
274f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndexRunnable.Results results = mResults;
275f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (results == null) {
276f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return null;
277f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
278f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (order == SortOrder.ASCENDING) {
279f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return results.mtpObjects[position];
280f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
281f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return results.mtpObjects[results.mtpObjects.length - 1 - position];
282f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
283f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
284f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
285f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
286f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param position Index of item to map from a view of the data that does not
287f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *            include labels and is in the specified order
288f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param order
289f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return position in a view of the data that does include labels, or -1 if the index isn't
290f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *         ready
291f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
292f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public int getPositionFromPositionWithoutLabels(int position, SortOrder order) {
293f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        /* Although this is O(log(number of buckets)), and thus should not be used
294f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu           in hotspots, even if the attached device has items for every day for
295f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu           a five-year timeframe, it would still only take 11 iterations at most,
296f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu           so shouldn't be a huge issue. */
297f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndexRunnable.Results results = mResults;
298f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (results == null) {
299f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return -1;
300f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
301f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (order == SortOrder.DESCENDING) {
302f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      position = results.mtpObjects.length - 1 - position;
303f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
304f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int bucketNumber = 0;
305f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int iMin = 0;
306f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int iMax = results.buckets.length - 1;
307f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    while (iMax >= iMin) {
308f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      int iMid = (iMax + iMin) / 2;
309f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (results.buckets[iMid].itemsStartIndex + results.buckets[iMid].numItems
310f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          <= position) {
311f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        iMin = iMid + 1;
312f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      } else if (results.buckets[iMid].itemsStartIndex > position) {
313f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        iMax = iMid - 1;
314f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      } else {
315f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        bucketNumber = iMid;
316f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        break;
317f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
318f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
319f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    int mappedPos = results.buckets[bucketNumber].unifiedStartIndex + position
320f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        - results.buckets[bucketNumber].itemsStartIndex + 1;
321f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (order == SortOrder.DESCENDING) {
322f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mappedPos = results.unifiedLookupIndex.length - mappedPos;
323f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
324f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return mappedPos;
325f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
326f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
327f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
328f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param position Index of item to map from a view of the data that
329f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *            includes labels and is in the specified order
330f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param order
331f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return position in a view of the data that does not include labels, or -1 if the index isn't
332f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *         ready
333f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
334f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public int getPositionWithoutLabelsFromPosition(int position, SortOrder order) {
335f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndexRunnable.Results results = mResults;
336f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (results == null) {
337f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return -1;
338f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
339f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (order == SortOrder.ASCENDING) {
340f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      DateBucket bucket = results.buckets[results.unifiedLookupIndex[position]];
341f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (bucket.unifiedStartIndex == position) {
342f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        position++;
343f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
344f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return bucket.itemsStartIndex + position - 1 - bucket.unifiedStartIndex;
345f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
346f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      int zeroIndex = results.unifiedLookupIndex.length - 1 - position;
347f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      DateBucket bucket = results.buckets[results.unifiedLookupIndex[zeroIndex]];
348f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      if (bucket.unifiedEndIndex == zeroIndex) {
349f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu        zeroIndex--;
350f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      }
351f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return results.mtpObjects.length - 1 - bucket.itemsStartIndex
352f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          - zeroIndex + bucket.unifiedStartIndex;
353f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
354f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
355f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
356f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
357f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return The number of media items in the index
358f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
359f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public int sizeWithoutLabels() {
360f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndexRunnable.Results results = mResults;
361f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return results != null ? results.mtpObjects.length : 0;
362f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
363f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
364f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
365f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param bucketNumber Index of bucket in the specified order
366f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param order
367f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return position of bucket's first item in a view of the data that includes labels
368f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
369f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public int getFirstPositionForBucketNumber(int bucketNumber, SortOrder order) {
370f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndexRunnable.Results results = mResults;
371f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (order == SortOrder.ASCENDING) {
372f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return results.buckets[bucketNumber].unifiedStartIndex;
373f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
374f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return results.unifiedLookupIndex.length
375f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          - results.buckets[results.buckets.length - 1 - bucketNumber].unifiedEndIndex
376f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          - 1;
377f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
378f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
379f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
380f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
381f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param position Index of item in the view of the data that includes labels and is in
382f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *                 the specified order
383f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param order
384f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return Index of the bucket that contains the specified item
385f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
386f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public int getBucketNumberForPosition(int position, SortOrder order) {
387f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndexRunnable.Results results = mResults;
388f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (order == SortOrder.ASCENDING) {
389f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return results.unifiedLookupIndex[position];
390f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
391f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return results.buckets.length - 1
392f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          - results.unifiedLookupIndex[results.unifiedLookupIndex.length - 1
393f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          - position];
394f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
395f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
396f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
397f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
398f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param position Index of item in the view of the data that includes labels and is in
399f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   *                 the specified order
400f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param order
401f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return Whether the specified item is the first item in its bucket
402f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
403f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public boolean isFirstInBucket(int position, SortOrder order) {
404f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndexRunnable.Results results = mResults;
405f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (order == SortOrder.ASCENDING) {
406f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return results.buckets[results.unifiedLookupIndex[position]].unifiedStartIndex
407f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          == position;
408f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    } else {
409f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      position = results.unifiedLookupIndex.length - 1 - position;
410f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return results.buckets[results.unifiedLookupIndex[position]].unifiedEndIndex
411f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu          == position;
412f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
413f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
414f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
415f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
416f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param order
417f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return Array of buckets in the specified order
418f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
419f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  public DateBucket[] getBuckets(SortOrder order) {
420f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    MtpDeviceIndexRunnable.Results results = mResults;
421f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (results == null) {
422f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return null;
423f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
424f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return (order == SortOrder.ASCENDING) ? results.buckets : results.reversedBuckets;
425f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
426f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
427f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected void resetState() {
428f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mGeneration++;
429f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mResults = null;
430f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
431f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
432f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  /**
433f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param device
434f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @param generation
435f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   * @return whether the index is at the given generation and the given device is connected
436f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu   */
437f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected boolean isAtGeneration(MtpDevice device, long generation) {
438f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return (mGeneration == generation) && (mDevice == device);
439f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
440f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
441f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected synchronized boolean setIndexingResults(MtpDevice device, long generation,
442f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      MtpDeviceIndexRunnable.Results results) {
443f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (!isAtGeneration(device, generation)) {
444f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      return false;
445f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
446f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    mResults = results;
447f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    onIndexFinish(true /*successful*/);
448f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return true;
449f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
450f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
451f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected synchronized void onIndexFinish(boolean successful) {
452f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (!successful) {
453f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      resetState();
454f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
455f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mProgressListener != null) {
456f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mProgressListener.onIndexingFinished();
457f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
458f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
459f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
460f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected synchronized void onSorting() {
461f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mProgressListener != null) {
462f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mProgressListener.onSortingStarted();
463f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
464f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
465f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
466f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected synchronized void onObjectIndexed(IngestObjectInfo object, int numVisited) {
467f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    if (mProgressListener != null) {
468f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu      mProgressListener.onObjectIndexed(object, numVisited);
469f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    }
470f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
471f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu
472f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  protected long getGeneration() {
473f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu    return mGeneration;
474f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu  }
475f640d379259bb114a50e3200f49961b89d60f2c2Bobby Georgescu}
476