13c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen/*
23c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen * Copyright (C) 2009 The Android Open Source Project
33c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen *
43c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen * Licensed under the Apache License, Version 2.0 (the "License");
53c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen * you may not use this file except in compliance with the License.
63c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen * You may obtain a copy of the License at
73c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen *
83c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen *      http://www.apache.org/licenses/LICENSE-2.0
93c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen *
103c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen * Unless required by applicable law or agreed to in writing, software
113c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen * distributed under the License is distributed on an "AS IS" BASIS,
123c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen * See the License for the specific language governing permissions and
143c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen * limitations under the License.
153c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen */
163c02f2877dc2f8f0b5c01d03fa2b487c040e4000Wei-Ta Chen
17f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparkspackage com.cooliris.media;
18f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
19f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparksimport java.util.ArrayList;
20f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparksimport java.util.HashMap;
21897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnarajimport java.util.HashSet;
221b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkatimport java.util.Set;
23f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
24897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnarajimport android.content.ContentResolver;
25f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparksimport android.content.Context;
26897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnarajimport android.database.ContentObserver;
271c729acdafe147abda6b3479eafb17607f172780Venkatimport android.util.Log;
28f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparksimport android.view.Gravity;
29f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparksimport android.widget.Toast;
30897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnarajimport android.net.Uri;
31897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnarajimport android.os.Handler;
32f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparksimport android.os.Process;
33f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
34d93f177bf2bc26f4ad64ca2f7725da8b0347a77fVenkatimport com.cooliris.app.App;
3529dcedb79b7eb9e3d65adc5d2ea95c1dd5c01df9Chih-Chung Changimport com.cooliris.app.Res;
36f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparksimport com.cooliris.media.MediaClustering.Cluster;
37f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
38f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparkspublic final class MediaFeed implements Runnable {
391c729acdafe147abda6b3479eafb17607f172780Venkat    private final String TAG = "MediaFeed";
40f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public static final int OPERATION_DELETE = 0;
41f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public static final int OPERATION_ROTATE = 1;
42f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public static final int OPERATION_CROP = 2;
43f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
44f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private static final int NUM_ITEMS_LOOKAHEAD = 60;
450e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen    private static final int NUM_INTERRUPT_RETRIES = 30;
460e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen    private static final int JOIN_TIMEOUT = 50;
47f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
48f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private IndexRange mVisibleRange = new IndexRange();
49f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private IndexRange mBufferedRange = new IndexRange();
50f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private ArrayList<MediaSet> mMediaSets = new ArrayList<MediaSet>();
51f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private Listener mListener;
52f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private DataSource mDataSource;
53f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private boolean mListenerNeedsUpdate = false;
54d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks    private boolean mMediaFeedNeedsToRun = false;
55f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private MediaSet mSingleWrapper = new MediaSet();
56f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private boolean mInClusteringMode = false;
57f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private HashMap<MediaSet, MediaClustering> mClusterSets = new HashMap<MediaSet, MediaClustering>(32);
58f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private int mExpandedMediaSetIndex = Shared.INVALID;
59f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private MediaFilter mMediaFilter;
60f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private MediaSet mMediaFilteredSet;
61f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private Context mContext;
62f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private Thread mDataSourceThread = null;
63f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private Thread mAlbumSourceThread = null;
64f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private boolean mListenerNeedsLayout;
65f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private boolean mWaitingForMediaScanner;
66f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private boolean mSingleImageMode;
67f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private boolean mLoading;
68897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj    private HashMap<String, ContentObserver> mContentObservers = new HashMap<String, ContentObserver>();
6962dd11281ef6e12049dd6798b184157e9583d7d4Venkat    private ArrayList<String[]> mRequestedRefresh = new ArrayList<String[]>();
700e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen    private volatile boolean mIsShutdown = false;
71f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
72f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public interface Listener {
73f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        public abstract void onFeedAboutToChange(MediaFeed feed);
7462dd11281ef6e12049dd6798b184157e9583d7d4Venkat
75f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        public abstract void onFeedChanged(MediaFeed feed, boolean needsLayout);
76f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
77f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
78f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public MediaFeed(Context context, DataSource dataSource, Listener listener) {
79f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mContext = context;
80f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mListener = listener;
81f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mDataSource = dataSource;
82f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mSingleWrapper.setNumExpectedItems(1);
83f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mLoading = true;
84f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
85d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks
86f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void shutdown() {
870e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen        mIsShutdown = true;
88f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mDataSourceThread != null) {
89f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mDataSource.shutdown();
900e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen            repeatShuttingDownThread(mDataSourceThread);
91f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mDataSourceThread = null;
92f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
93f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mAlbumSourceThread != null) {
940e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen            repeatShuttingDownThread(mAlbumSourceThread);
95f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mAlbumSourceThread = null;
96f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
97f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        int numSets = mMediaSets.size();
98f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        for (int i = 0; i < numSets; ++i) {
99f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaSet set = mMediaSets.get(i);
100f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            set.clear();
101f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
102f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        synchronized (mMediaSets) {
103f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mMediaSets.clear();
104f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
105f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        int numClusters = mClusterSets.size();
106f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        for (int i = 0; i < numClusters; ++i) {
107f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaClustering mc = mClusterSets.get(i);
108f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (mc != null) {
109f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                mc.clear();
110f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
111f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
112f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mClusterSets.clear();
113f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mListener = null;
114f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mDataSource = null;
115f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mSingleWrapper = null;
116f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
117f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
1180e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen    private void repeatShuttingDownThread(Thread targetThread) {
1190e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen        for (int i = 0; i < NUM_INTERRUPT_RETRIES && targetThread.isAlive(); ++i) {
1200e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen            targetThread.interrupt();
1210e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen            try {
1220e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen                targetThread.join(JOIN_TIMEOUT);
1230e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen            } catch (InterruptedException e) {
1240e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen                Log.w(TAG, "Cannot stop the thread: " + targetThread.getName(), e);
1250e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen                Thread.currentThread().interrupt();
1260e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen                return;
1270e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen            }
1280e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen        }
1290e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen
1300e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen        if (targetThread.isAlive()) {
1310e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen            Log.w(TAG, "Cannot stop the thread: " + targetThread.getName());
1320e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen        }
1330e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen    }
1340e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen
135f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void setVisibleRange(int begin, int end) {
136d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        if (begin != mVisibleRange.begin || end != mVisibleRange.end) {
137d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            mVisibleRange.begin = begin;
138d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            mVisibleRange.end = end;
139d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            int numItems = 96;
140d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            int numItemsBy2 = numItems / 2;
141d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            int numItemsBy4 = numItems / 4;
142d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            mBufferedRange.begin = (begin / numItemsBy2) * numItemsBy2 - numItemsBy4;
143d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            mBufferedRange.end = mBufferedRange.begin + numItems;
144d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            mMediaFeedNeedsToRun = true;
145d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        }
146f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
147f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
148f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void setFilter(MediaFilter filter) {
149f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mMediaFilter = filter;
150f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mMediaFilteredSet = null;
151f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mListener != null) {
152f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mListener.onFeedAboutToChange(this);
153f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
154d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        mMediaFeedNeedsToRun = true;
155f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
156f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
157f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void removeFilter() {
158f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mMediaFilter = null;
159f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mMediaFilteredSet = null;
160f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mListener != null) {
161f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mListener.onFeedAboutToChange(this);
162f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            updateListener(true);
163f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
164d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        mMediaFeedNeedsToRun = true;
165f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
166f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
167f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public ArrayList<MediaSet> getMediaSets() {
168f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return mMediaSets;
169f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
170f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
171d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks    public MediaSet getMediaSet(final long setId) {
172f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (setId != Shared.INVALID) {
173d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            try {
174d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                int mMediaSetsSize = mMediaSets.size();
175d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                for (int i = 0; i < mMediaSetsSize; i++) {
1761b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj                    final MediaSet set = mMediaSets.get(i);
1771b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj                    if (set.mId == setId) {
1781b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj                        set.mFlagForDelete = false;
1791b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj                        return set;
180d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                    }
181f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
182d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            } catch (Exception e) {
183d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                return null;
184f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
185f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
186f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return null;
187f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
188f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
189f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public MediaSet getFilteredSet() {
190f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return mMediaFilteredSet;
191f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
192f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
193f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public MediaSet addMediaSet(final long setId, DataSource dataSource) {
194f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        MediaSet mediaSet = new MediaSet(dataSource);
195f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mediaSet.mId = setId;
196f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mMediaSets.add(mediaSet);
197d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        if (mDataSourceThread != null && !mDataSourceThread.isAlive()) {
198d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            mDataSourceThread.start();
199d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        }
200d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        mMediaFeedNeedsToRun = true;
201f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return mediaSet;
202f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
203f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
204f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public DataSource getDataSource() {
205f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return mDataSource;
206f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
207f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
208f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public MediaClustering getClustering() {
209f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mExpandedMediaSetIndex != Shared.INVALID && mExpandedMediaSetIndex < mMediaSets.size()) {
210f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            return mClusterSets.get(mMediaSets.get(mExpandedMediaSetIndex));
211f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
212f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return null;
213f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
214f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
215f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public ArrayList<Cluster> getClustersForSet(final MediaSet set) {
216f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        ArrayList<Cluster> clusters = null;
217f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mClusterSets != null && mClusterSets.containsKey(set)) {
218f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaClustering mediaClustering = mClusterSets.get(set);
219f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (mediaClustering != null) {
220f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                clusters = mediaClustering.getClusters();
221f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
222f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
223f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return clusters;
224f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
225f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
226f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void addItemToMediaSet(MediaItem item, MediaSet mediaSet) {
227f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        item.mParentMediaSet = mediaSet;
228f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mediaSet.addItem(item);
229d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        synchronized (mClusterSets) {
230f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (item.mClusteringState == MediaItem.NOT_CLUSTERED) {
231f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                MediaClustering clustering = mClusterSets.get(mediaSet);
232f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                if (clustering == null) {
233f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    clustering = new MediaClustering(mediaSet.isPicassaAlbum());
234f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    mClusterSets.put(mediaSet, clustering);
235f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
236f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                clustering.setTimeRange(mediaSet.mMaxTimestamp - mediaSet.mMinTimestamp, mediaSet.getNumExpectedItems());
237f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                clustering.addItemForClustering(item);
238f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                item.mClusteringState = MediaItem.CLUSTERED;
239f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
240f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
241d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        mMediaFeedNeedsToRun = true;
242f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
243f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
244f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void performOperation(final int operation, final ArrayList<MediaBucket> mediaBuckets, final Object data) {
245f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        int numBuckets = mediaBuckets.size();
246f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        final ArrayList<MediaBucket> copyMediaBuckets = new ArrayList<MediaBucket>(numBuckets);
247f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        for (int i = 0; i < numBuckets; ++i) {
248f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            copyMediaBuckets.add(mediaBuckets.get(i));
249f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
250f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (operation == OPERATION_DELETE && mListener != null) {
251f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mListener.onFeedAboutToChange(this);
252f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
253f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        Thread operationThread = new Thread(new Runnable() {
254f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            public void run() {
255f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                ArrayList<MediaBucket> mediaBuckets = copyMediaBuckets;
256f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                if (operation == OPERATION_DELETE) {
257f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    int numBuckets = mediaBuckets.size();
258f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    for (int i = 0; i < numBuckets; ++i) {
259f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        MediaBucket bucket = mediaBuckets.get(i);
260f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        MediaSet set = bucket.mediaSet;
261f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        ArrayList<MediaItem> items = bucket.mediaItems;
262f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        if (set != null && items == null) {
263f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            // Remove the entire bucket.
264f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            removeMediaSet(set);
265f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        } else if (set != null && items != null) {
266f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            // We need to remove these items from the set.
267f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            int numItems = items.size();
2681bb0c42b2a62f580eea4764d6a4434ffecfbf353Dave Sparks                            // We also need to delete the items from the
2691bb0c42b2a62f580eea4764d6a4434ffecfbf353Dave Sparks                            // cluster.
270f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            MediaClustering clustering = mClusterSets.get(set);
271f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            for (int j = 0; j < numItems; ++j) {
272f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                MediaItem item = items.get(j);
273f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                removeItemFromMediaSet(item, set);
274f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                if (clustering != null) {
275f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    clustering.removeItemFromClustering(item);
276f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                }
277f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            }
278f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            set.updateNumExpectedItems();
279f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            set.generateTitle(true);
280f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        }
281f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    }
282f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    updateListener(true);
283d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                    mMediaFeedNeedsToRun = true;
284f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    if (mDataSource != null) {
285f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        mDataSource.performOperation(OPERATION_DELETE, mediaBuckets, null);
286f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    }
287f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                } else {
288f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    mDataSource.performOperation(operation, mediaBuckets, data);
289f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
290f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
291f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        });
292f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        operationThread.setName("Operation " + operation);
293f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        operationThread.start();
294f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
295f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
296f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void removeMediaSet(MediaSet set) {
2972b04f591f758b7af03c43d90e91b939cbd515506Venkat Krishnaraj        synchronized (mMediaSets) {
2981bb0c42b2a62f580eea4764d6a4434ffecfbf353Dave Sparks            mMediaSets.remove(set);
2992b04f591f758b7af03c43d90e91b939cbd515506Venkat Krishnaraj        }
300d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        mMediaFeedNeedsToRun = true;
301f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
302f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
303f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private void removeItemFromMediaSet(MediaItem item, MediaSet mediaSet) {
304f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mediaSet.removeItem(item);
305d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        synchronized (mClusterSets) {
306f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaClustering clustering = mClusterSets.get(mediaSet);
307f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (clustering != null) {
308f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                clustering.removeItemFromClustering(item);
309f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
310f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
311d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        mMediaFeedNeedsToRun = true;
312f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
313f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
314f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void updateListener(boolean needsLayout) {
315f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mListenerNeedsUpdate = true;
316f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mListenerNeedsLayout = needsLayout;
317f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
318f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
319f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public int getNumSlots() {
320f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        int currentMediaSetIndex = mExpandedMediaSetIndex;
321f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        ArrayList<MediaSet> mediaSets = mMediaSets;
322f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        int mediaSetsSize = mediaSets.size();
323f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
324f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mInClusteringMode == false) {
325f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (currentMediaSetIndex == Shared.INVALID || currentMediaSetIndex >= mediaSetsSize) {
326f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                return mediaSetsSize;
327f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            } else {
328f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                MediaSet setToUse = (mMediaFilteredSet == null) ? mediaSets.get(currentMediaSetIndex) : mMediaFilteredSet;
3295e0474e8e1942c41234eb251f948c2fbb7445b02Venkat Krishnaraj                return setToUse.getNumExpectedItems();
330f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
331f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        } else if (currentMediaSetIndex != Shared.INVALID && currentMediaSetIndex < mediaSetsSize) {
332f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaSet set = mediaSets.get(currentMediaSetIndex);
333f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaClustering clustering = mClusterSets.get(set);
334f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (clustering != null) {
335f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                return clustering.getClustersForDisplay().size();
336f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
337f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
338f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return 0;
339f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
34062dd11281ef6e12049dd6798b184157e9583d7d4Venkat
3417cde3b179f4d12f53c2a1db1e4f903bd06b7011eWei-Ta Chen    public void copySlotStateFrom(MediaFeed another) {
3427cde3b179f4d12f53c2a1db1e4f903bd06b7011eWei-Ta Chen        mExpandedMediaSetIndex = another.mExpandedMediaSetIndex;
3437cde3b179f4d12f53c2a1db1e4f903bd06b7011eWei-Ta Chen        mInClusteringMode = another.mInClusteringMode;
3447cde3b179f4d12f53c2a1db1e4f903bd06b7011eWei-Ta Chen    }
3457cde3b179f4d12f53c2a1db1e4f903bd06b7011eWei-Ta Chen
34688dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat    public ArrayList<Integer> getBreaks() {
34788dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat        if (true)
34888dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            return null;
34988dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat        int currentMediaSetIndex = mExpandedMediaSetIndex;
35088dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat        ArrayList<MediaSet> mediaSets = mMediaSets;
35188dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat        int mediaSetsSize = mediaSets.size();
35288dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat        if (currentMediaSetIndex == Shared.INVALID || currentMediaSetIndex >= mediaSetsSize)
35388dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            return null;
35488dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat        MediaSet set = mediaSets.get(currentMediaSetIndex);
35588dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat        MediaClustering clustering = mClusterSets.get(set);
35688dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat        if (clustering != null) {
35788dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            clustering.compute(null, true);
35888dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            final ArrayList<Cluster> clusters = clustering.getClustersForDisplay();
35988dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            int numClusters = clusters.size();
36088dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            final ArrayList<Integer> retVal = new ArrayList<Integer>(numClusters);
36188dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            int size = 0;
36288dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            for (int i = 0; i < numClusters; ++i) {
36388dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat                size += clusters.get(i).getItems().size();
36488dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat                retVal.add(size);
36588dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            }
36688dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            return retVal;
36788dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat        } else {
36888dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat            return null;
36988dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat        }
37088dc4ec391fdd373821aa94ae93ca0c231eb98bbVenkat    }
371f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
372f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public MediaSet getSetForSlot(int slotIndex) {
373f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (slotIndex < 0) {
374f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            return null;
375f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
376f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
377f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        ArrayList<MediaSet> mediaSets = mMediaSets;
378f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        int mediaSetsSize = mediaSets.size();
379f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        int currentMediaSetIndex = mExpandedMediaSetIndex;
380f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
381f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mInClusteringMode == false) {
382f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (currentMediaSetIndex == Shared.INVALID || currentMediaSetIndex >= mediaSetsSize) {
383f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                if (slotIndex >= mediaSetsSize) {
384f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    return null;
385f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
386f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                return mMediaSets.get(slotIndex);
387f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
388f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (mSingleWrapper.getNumItems() == 0) {
389f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                mSingleWrapper.addItem(null);
390f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
391f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaSet setToUse = (mMediaFilteredSet == null) ? mMediaSets.get(currentMediaSetIndex) : mMediaFilteredSet;
392f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            ArrayList<MediaItem> items = setToUse.getItems();
393f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (slotIndex >= setToUse.getNumItems()) {
394f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                return null;
395f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
396f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mSingleWrapper.getItems().set(0, items.get(slotIndex));
397f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            return mSingleWrapper;
398f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        } else if (currentMediaSetIndex != Shared.INVALID && currentMediaSetIndex < mediaSetsSize) {
399f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaSet set = mediaSets.get(currentMediaSetIndex);
400f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaClustering clustering = mClusterSets.get(set);
401f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (clustering != null) {
402f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                ArrayList<MediaClustering.Cluster> clusters = clustering.getClustersForDisplay();
403f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                if (clusters.size() > slotIndex) {
404f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    MediaClustering.Cluster cluster = clusters.get(slotIndex);
405f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    cluster.generateCaption(mContext);
406f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    return cluster;
407f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
408f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
409f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
410f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return null;
411f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
412f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
413f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public boolean getWaitingForMediaScanner() {
414f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return mWaitingForMediaScanner;
415f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
416d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks
417f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public boolean isLoading() {
418f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return mLoading;
419f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
420f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
421f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void start() {
422f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        final MediaFeed feed = this;
42362f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat        onResume();
424f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mLoading = true;
425d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        mDataSourceThread = new Thread(this);
426d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        mDataSourceThread.setName("MediaFeed");
4270e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen        mIsShutdown = false;
428f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mAlbumSourceThread = new Thread(new Runnable() {
429f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            public void run() {
430f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                if (mContext == null)
431f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    return;
432f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
433f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                DataSource dataSource = mDataSource;
4341bb0c42b2a62f580eea4764d6a4434ffecfbf353Dave Sparks                // We must wait while the SD card is mounted or the MediaScanner
4351bb0c42b2a62f580eea4764d6a4434ffecfbf353Dave Sparks                // is running.
436d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                if (dataSource != null) {
4371b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj                    loadMediaSets();
438d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                }
439f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                mWaitingForMediaScanner = false;
440f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                while (ImageManager.isMediaScannerScanning(mContext.getContentResolver())) {
441f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    // MediaScanner is still running, wait
44288ed7e72a2a0bfdbef7f72aea2b2ddfd74961bdbVenkat Krishnaraj                    if (Thread.interrupted())
44388ed7e72a2a0bfdbef7f72aea2b2ddfd74961bdbVenkat Krishnaraj                        return;
444f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    mWaitingForMediaScanner = true;
445f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    try {
446f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        if (mContext == null)
447f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            return;
44829dcedb79b7eb9e3d65adc5d2ea95c1dd5c01df9Chih-Chung Chang                        showToast(mContext.getResources().getString(Res.string.initializing), Toast.LENGTH_LONG);
4491b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj                        if (dataSource != null) {
4501b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj                            loadMediaSets();
4511b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj                        }
4521b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj                        Thread.sleep(10000);
453f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    } catch (InterruptedException e) {
45488ed7e72a2a0bfdbef7f72aea2b2ddfd74961bdbVenkat Krishnaraj                        return;
455f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    }
456f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
457f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                if (mWaitingForMediaScanner) {
45829dcedb79b7eb9e3d65adc5d2ea95c1dd5c01df9Chih-Chung Chang                    showToast(mContext.getResources().getString(Res.string.loading_new), Toast.LENGTH_LONG);
459d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                    mWaitingForMediaScanner = false;
4601b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj                    loadMediaSets();
461f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
462f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                mLoading = false;
463f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
464f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        });
465f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mAlbumSourceThread.setName("MediaSets");
466f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mAlbumSourceThread.start();
467f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
468897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj
4691b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj    private void loadMediaSets() {
4701b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj        if (mDataSource == null)
4711b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj            return;
4721b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj        final ArrayList<MediaSet> sets = mMediaSets;
47362f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat        synchronized (sets) {
47480182dccb216689e392da1c749f32f6c0cda6f42Venkat            final int numSets = sets.size();
47580182dccb216689e392da1c749f32f6c0cda6f42Venkat            for (int i = 0; i < numSets; ++i) {
47680182dccb216689e392da1c749f32f6c0cda6f42Venkat                final MediaSet set = sets.get(i);
47780182dccb216689e392da1c749f32f6c0cda6f42Venkat                set.mFlagForDelete = true;
47880182dccb216689e392da1c749f32f6c0cda6f42Venkat            }
47962f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat            mDataSource.refresh(MediaFeed.this, mDataSource.getDatabaseUris());
48062f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat            mDataSource.loadMediaSets(MediaFeed.this);
48180182dccb216689e392da1c749f32f6c0cda6f42Venkat            final ArrayList<MediaSet> setsToRemove = new ArrayList<MediaSet>();
48280182dccb216689e392da1c749f32f6c0cda6f42Venkat            for (int i = 0; i < numSets; ++i) {
48380182dccb216689e392da1c749f32f6c0cda6f42Venkat                final MediaSet set = sets.get(i);
48480182dccb216689e392da1c749f32f6c0cda6f42Venkat                if (set.mFlagForDelete) {
48580182dccb216689e392da1c749f32f6c0cda6f42Venkat                    setsToRemove.add(set);
48680182dccb216689e392da1c749f32f6c0cda6f42Venkat                }
4871b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj            }
48880182dccb216689e392da1c749f32f6c0cda6f42Venkat            int numSetsToRemove = setsToRemove.size();
48980182dccb216689e392da1c749f32f6c0cda6f42Venkat            for (int i = 0; i < numSetsToRemove; ++i) {
49080182dccb216689e392da1c749f32f6c0cda6f42Venkat                sets.remove(setsToRemove.get(i));
49180182dccb216689e392da1c749f32f6c0cda6f42Venkat            }
49280182dccb216689e392da1c749f32f6c0cda6f42Venkat            setsToRemove.clear();
4931b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj        }
49480182dccb216689e392da1c749f32f6c0cda6f42Venkat        mMediaFeedNeedsToRun = true;
4951b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj        updateListener(false);
4961b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj    }
497f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
498f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private void showToast(final String string, final int duration) {
499f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        showToast(string, duration, false);
500f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
501f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
502f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private void showToast(final String string, final int duration, final boolean centered) {
503d93f177bf2bc26f4ad64ca2f7725da8b0347a77fVenkat        if (mContext != null && !App.get(mContext).isPaused()) {
50462f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat            App.get(mContext).getHandler().post(new Runnable() {
505f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                public void run() {
506f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    if (mContext != null) {
507f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        Toast toast = Toast.makeText(mContext, string, duration);
508f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        if (centered) {
509f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            toast.setGravity(Gravity.CENTER, 0, 0);
510f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        }
511f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        toast.show();
512f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    }
513f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
514f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            });
515f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
516f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
517f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
518f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void run() {
519f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        DataSource dataSource = mDataSource;
520d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        int sleepMs = 10;
521f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
522f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (dataSource != null) {
5230e0a636482418d6836bb783d2b00e9e3706dfc14Wei-Ta Chen            while (!Thread.interrupted() && !mIsShutdown) {
52462dd11281ef6e12049dd6798b184157e9583d7d4Venkat                String[] databaseUris = null;
52562dd11281ef6e12049dd6798b184157e9583d7d4Venkat                boolean performRefresh = false;
52662dd11281ef6e12049dd6798b184157e9583d7d4Venkat                synchronized (mRequestedRefresh) {
52762dd11281ef6e12049dd6798b184157e9583d7d4Venkat                    if (mRequestedRefresh.size() > 0) {
52862dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        // We prune this first.
52962dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        int numRequests = mRequestedRefresh.size();
53062dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        for (int i = 0; i < numRequests; ++i) {
53162dd11281ef6e12049dd6798b184157e9583d7d4Venkat                            databaseUris = ArrayUtils.addAll(databaseUris, mRequestedRefresh.get(i));
53262dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        }
53362dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        mRequestedRefresh.clear();
53462dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        performRefresh = true;
53562dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        // We need to eliminate duplicate uris in this array
53662dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        final HashMap<String, String> uris = new HashMap<String, String>();
53762dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        if (databaseUris != null) {
53862dd11281ef6e12049dd6798b184157e9583d7d4Venkat                            int numUris = databaseUris.length;
53962dd11281ef6e12049dd6798b184157e9583d7d4Venkat                            for (int i = 0; i < numUris; ++i) {
54062dd11281ef6e12049dd6798b184157e9583d7d4Venkat                                final String uri = databaseUris[i];
54162dd11281ef6e12049dd6798b184157e9583d7d4Venkat                                if (uri != null)
54262dd11281ef6e12049dd6798b184157e9583d7d4Venkat                                    uris.put(uri, uri);
54362dd11281ef6e12049dd6798b184157e9583d7d4Venkat                            }
54462dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        }
54562dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        databaseUris = new String[0];
54662dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        databaseUris = (String[]) uris.keySet().toArray(databaseUris);
54762dd11281ef6e12049dd6798b184157e9583d7d4Venkat                    }
54862dd11281ef6e12049dd6798b184157e9583d7d4Venkat                }
549b832709e16e0d018447f3d20755d3c22d09e2ba0Venkat                boolean settingFeedAboutToChange = false;
55062dd11281ef6e12049dd6798b184157e9583d7d4Venkat                if (performRefresh) {
5511c729acdafe147abda6b3479eafb17607f172780Venkat                    if (dataSource != null) {
552b832709e16e0d018447f3d20755d3c22d09e2ba0Venkat                        if (mListener != null) {
553b832709e16e0d018447f3d20755d3c22d09e2ba0Venkat                            settingFeedAboutToChange = true;
554b832709e16e0d018447f3d20755d3c22d09e2ba0Venkat                            mListener.onFeedAboutToChange(this);
555b832709e16e0d018447f3d20755d3c22d09e2ba0Venkat                        }
55662dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        dataSource.refresh(this, databaseUris);
55771660902f0aa83113bf11a2933e92b08c524fed5Venkat                        mMediaFeedNeedsToRun = true;
5581c729acdafe147abda6b3479eafb17607f172780Venkat                    }
5591c729acdafe147abda6b3479eafb17607f172780Venkat                }
5601c729acdafe147abda6b3479eafb17607f172780Venkat                if (mListenerNeedsUpdate && !mMediaFeedNeedsToRun) {
561f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    mListenerNeedsUpdate = false;
562f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    if (mListener != null)
56346afd9b71156248a494ea618c37b5a373fd8e386Venkat                        synchronized (mMediaSets) {
56446afd9b71156248a494ea618c37b5a373fd8e386Venkat                            mListener.onFeedChanged(this, mListenerNeedsLayout);
56546afd9b71156248a494ea618c37b5a373fd8e386Venkat                        }
566f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    try {
567f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        Thread.sleep(sleepMs);
568f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    } catch (InterruptedException e) {
569f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        return;
570f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    }
571f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                } else {
572f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    try {
573f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        Thread.sleep(sleepMs);
574f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    } catch (InterruptedException e) {
575f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        return;
576f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    }
577f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
578d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                sleepMs = 300;
579d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                if (!mMediaFeedNeedsToRun)
580d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                    continue;
581d93f177bf2bc26f4ad64ca2f7725da8b0347a77fVenkat                App app = App.get(mContext);
58262f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                if (app == null || app.isPaused())
58362f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                    continue;
584b832709e16e0d018447f3d20755d3c22d09e2ba0Venkat                if (settingFeedAboutToChange) {
585b832709e16e0d018447f3d20755d3c22d09e2ba0Venkat                    updateListener(true);
586b832709e16e0d018447f3d20755d3c22d09e2ba0Venkat                }
587d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                mMediaFeedNeedsToRun = false;
588f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                ArrayList<MediaSet> mediaSets = mMediaSets;
589f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                synchronized (mediaSets) {
590f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    int expandedSetIndex = mExpandedMediaSetIndex;
591f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    if (expandedSetIndex >= mMediaSets.size()) {
592f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        expandedSetIndex = Shared.INVALID;
593f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    }
594f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    if (expandedSetIndex == Shared.INVALID) {
595f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        // We purge the sets outside this visibleRange.
5962b04f591f758b7af03c43d90e91b939cbd515506Venkat Krishnaraj                        int numSets = mediaSets.size();
597f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        IndexRange visibleRange = mVisibleRange;
598f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        IndexRange bufferedRange = mBufferedRange;
599f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        boolean scanMediaSets = true;
600f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        for (int i = 0; i < numSets; ++i) {
601f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            if (i >= visibleRange.begin && i <= visibleRange.end && scanMediaSets) {
602f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                MediaSet set = mediaSets.get(i);
603f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                int numItemsLoaded = set.mNumItemsLoaded;
604f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                if (numItemsLoaded < set.getNumExpectedItems() && numItemsLoaded < 8) {
60562f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                                    synchronized (set) {
60662f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                                        dataSource.loadItemsForSet(this, set, numItemsLoaded, 8);
607eb50ae54adfb694b1a424e7a36eed99dc0be1620Venkat                                        set.checkForDeletedItems();
60862f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                                    }
609f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    if (set.getNumExpectedItems() == 0) {
610f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                        mediaSets.remove(set);
611f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                        break;
612f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    }
613f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    if (mListener != null) {
6141c729acdafe147abda6b3479eafb17607f172780Venkat                                        mListenerNeedsUpdate = false;
6151c729acdafe147abda6b3479eafb17607f172780Venkat                                        mListener.onFeedChanged(this, mListenerNeedsLayout);
6161c729acdafe147abda6b3479eafb17607f172780Venkat                                        mListenerNeedsLayout = false;
617f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    }
618f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    sleepMs = 100;
619f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    scanMediaSets = false;
620f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                }
621d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                                if (!set.setContainsValidItems()) {
622d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                                    mediaSets.remove(set);
623d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                                    if (mListener != null) {
6241c729acdafe147abda6b3479eafb17607f172780Venkat                                        mListenerNeedsUpdate = false;
6251c729acdafe147abda6b3479eafb17607f172780Venkat                                        mListener.onFeedChanged(this, mListenerNeedsLayout);
6261c729acdafe147abda6b3479eafb17607f172780Venkat                                        mListenerNeedsLayout = false;
627d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                                    }
628d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                                    break;
629d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks                                }
630f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            }
631f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        }
6322b04f591f758b7af03c43d90e91b939cbd515506Venkat Krishnaraj                        numSets = mediaSets.size();
633f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        for (int i = 0; i < numSets; ++i) {
634f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            MediaSet set = mediaSets.get(i);
635f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            if (i >= bufferedRange.begin && i <= bufferedRange.end) {
636f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                if (scanMediaSets) {
637f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    int numItemsLoaded = set.mNumItemsLoaded;
638f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    if (numItemsLoaded < set.getNumExpectedItems() && numItemsLoaded < 8) {
63962f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                                        synchronized (set) {
64062f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                                            dataSource.loadItemsForSet(this, set, numItemsLoaded, 8);
641eb50ae54adfb694b1a424e7a36eed99dc0be1620Venkat                                            set.checkForDeletedItems();
64262f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                                        }
643f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                        if (set.getNumExpectedItems() == 0) {
644f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                            mediaSets.remove(set);
645f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                            break;
646f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                        }
647f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                        if (mListener != null) {
6481c729acdafe147abda6b3479eafb17607f172780Venkat                                            mListenerNeedsUpdate = false;
6491c729acdafe147abda6b3479eafb17607f172780Venkat                                            mListener.onFeedChanged(this, mListenerNeedsLayout);
6501c729acdafe147abda6b3479eafb17607f172780Venkat                                            mListenerNeedsLayout = false;
651f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                        }
652f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                        sleepMs = 100;
653f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                        scanMediaSets = false;
654f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    }
655f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                }
656897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                            } else if (!mListenerNeedsUpdate && (i < bufferedRange.begin || i > bufferedRange.end)) {
657f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                // Purge this set to its initial status.
658f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                MediaClustering clustering = mClusterSets.get(set);
659f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                if (clustering != null) {
660f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    clustering.clear();
661f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    mClusterSets.remove(set);
662f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                }
663f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                if (set.getNumItems() != 0)
664f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    set.clear();
665f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            }
666f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        }
667f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    }
668f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    if (expandedSetIndex != Shared.INVALID) {
669f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        int numSets = mMediaSets.size();
670f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        for (int i = 0; i < numSets; ++i) {
671f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            // Purge other sets.
672f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            if (i != expandedSetIndex) {
673f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                MediaSet set = mediaSets.get(i);
674f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                MediaClustering clustering = mClusterSets.get(set);
675f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                if (clustering != null) {
676f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    clustering.clear();
677f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    mClusterSets.remove(set);
678f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                }
679897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                                if (set.mNumItemsLoaded != 0)
680f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    set.clear();
681f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            }
682f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        }
683f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        // Make sure all the items are loaded for the album.
684f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        int numItemsLoaded = mediaSets.get(expandedSetIndex).mNumItemsLoaded;
685f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        int requestedItems = mVisibleRange.end;
686f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        // requestedItems count changes in clustering mode.
687f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        if (mInClusteringMode && mClusterSets != null) {
688f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            requestedItems = 0;
689f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            MediaClustering clustering = mClusterSets.get(mediaSets.get(expandedSetIndex));
690db87908d640e17ef0946824be158d86c6e2d6836Dave Sparks                            if (clustering != null) {
691db87908d640e17ef0946824be158d86c6e2d6836Dave Sparks                                ArrayList<Cluster> clusters = clustering.getClustersForDisplay();
692db87908d640e17ef0946824be158d86c6e2d6836Dave Sparks                                int numClusters = clusters.size();
693db87908d640e17ef0946824be158d86c6e2d6836Dave Sparks                                for (int i = 0; i < numClusters; i++) {
694db87908d640e17ef0946824be158d86c6e2d6836Dave Sparks                                    requestedItems += clusters.get(i).getNumExpectedItems();
695db87908d640e17ef0946824be158d86c6e2d6836Dave Sparks                                }
696f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            }
697f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        }
698f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        MediaSet set = mediaSets.get(expandedSetIndex);
699f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        if (numItemsLoaded < set.getNumExpectedItems()) {
700897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                            // We perform calculations for a window that gets
701897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                            // anchored to a multiple of NUM_ITEMS_LOOKAHEAD.
702897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                            // The start of the window is 0, x, 2x, 3x ... etc
703897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                            // where x = NUM_ITEMS_LOOKAHEAD.
70462f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                            synchronized (set) {
70562f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                                dataSource.loadItemsForSet(this, set, numItemsLoaded, (requestedItems / NUM_ITEMS_LOOKAHEAD)
70662f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                                        * NUM_ITEMS_LOOKAHEAD + NUM_ITEMS_LOOKAHEAD);
707eb50ae54adfb694b1a424e7a36eed99dc0be1620Venkat                                set.checkForDeletedItems();
70862f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat                            }
709f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            if (set.getNumExpectedItems() == 0) {
710f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                mediaSets.remove(set);
7111c729acdafe147abda6b3479eafb17607f172780Venkat                                mListenerNeedsUpdate = false;
7121c729acdafe147abda6b3479eafb17607f172780Venkat                                mListener.onFeedChanged(this, mListenerNeedsLayout);
7131c729acdafe147abda6b3479eafb17607f172780Venkat                                mListenerNeedsLayout = false;
714f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            }
715f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            if (numItemsLoaded != set.mNumItemsLoaded && mListener != null) {
7161c729acdafe147abda6b3479eafb17607f172780Venkat                                mListenerNeedsUpdate = false;
7171c729acdafe147abda6b3479eafb17607f172780Venkat                                mListener.onFeedChanged(this, mListenerNeedsLayout);
7181c729acdafe147abda6b3479eafb17607f172780Venkat                                mListenerNeedsLayout = false;
719f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            }
720f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        }
721f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    }
722f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    MediaFilter filter = mMediaFilter;
723f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    if (filter != null && mMediaFilteredSet == null) {
724f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        if (expandedSetIndex != Shared.INVALID) {
725f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            MediaSet set = mediaSets.get(expandedSetIndex);
726f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            ArrayList<MediaItem> items = set.getItems();
727f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            int numItems = set.getNumItems();
728f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            MediaSet filteredSet = new MediaSet();
729f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            filteredSet.setNumExpectedItems(numItems);
730f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            mMediaFilteredSet = filteredSet;
731f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            for (int i = 0; i < numItems; ++i) {
732f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                MediaItem item = items.get(i);
733f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                if (filter.pass(item)) {
734f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                    filteredSet.addItem(item);
735f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                                }
736f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            }
737f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            filteredSet.updateNumExpectedItems();
738f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                            filteredSet.generateTitle(true);
739f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        }
740f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                        updateListener(true);
741f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    }
742f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
743f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
744f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
745f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
746f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
747f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void expandMediaSet(int mediaSetIndex) {
748f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        // We need to check if this slot can be focused or not.
749f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mListener != null) {
750f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mListener.onFeedAboutToChange(this);
751f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
752f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mExpandedMediaSetIndex > 0 && mediaSetIndex == Shared.INVALID) {
753f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            // We are collapsing a previously expanded media set
7541bb0c42b2a62f580eea4764d6a4434ffecfbf353Dave Sparks            if (mediaSetIndex < mMediaSets.size() && mExpandedMediaSetIndex >= 0 && mExpandedMediaSetIndex < mMediaSets.size()) {
755f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                MediaSet set = mMediaSets.get(mExpandedMediaSetIndex);
756f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                if (set.getNumItems() == 0) {
757f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    set.clear();
758f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
759f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
760f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
761f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mExpandedMediaSetIndex = mediaSetIndex;
762f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mediaSetIndex < mMediaSets.size() && mediaSetIndex >= 0) {
763f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            // Notify Picasa that the user entered the album.
764f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            // MediaSet set = mMediaSets.get(mediaSetIndex);
7651bb0c42b2a62f580eea4764d6a4434ffecfbf353Dave Sparks            // PicasaService.requestSync(mContext,
7661bb0c42b2a62f580eea4764d6a4434ffecfbf353Dave Sparks            // PicasaService.TYPE_ALBUM_PHOTOS, set.mPicasaAlbumId);
767f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
768f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        updateListener(true);
769d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        mMediaFeedNeedsToRun = true;
770f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
771f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
772f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public boolean canExpandSet(int slotIndex) {
773f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        int mediaSetIndex = slotIndex;
774f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mediaSetIndex < mMediaSets.size() && mediaSetIndex >= 0) {
775f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaSet set = mMediaSets.get(mediaSetIndex);
776f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (set.getNumItems() > 0) {
777f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                MediaItem item = set.getItems().get(0);
778f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                if (item.mId == Shared.INVALID) {
779f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    return false;
780f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
781f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                return true;
782f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
783f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
784f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return false;
785f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
786f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
787f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public boolean hasExpandedMediaSet() {
788f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return (mExpandedMediaSetIndex != Shared.INVALID);
789f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
790f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
791f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public boolean restorePreviousClusteringState() {
792f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        boolean retVal = disableClusteringIfNecessary();
793f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (retVal) {
794f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (mListener != null) {
795f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                mListener.onFeedAboutToChange(this);
796f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
797f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            updateListener(true);
798d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            mMediaFeedNeedsToRun = true;
799f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
800f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return retVal;
801f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
802f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
803f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    private boolean disableClusteringIfNecessary() {
804f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mInClusteringMode) {
805f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            // Disable clustering.
806f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mInClusteringMode = false;
807d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            mMediaFeedNeedsToRun = true;
808f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            return true;
809f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
810f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return false;
811f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
812f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
813f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public boolean isClustered() {
814f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return mInClusteringMode;
815f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
816f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
817f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public MediaSet getCurrentSet() {
818f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mExpandedMediaSetIndex != Shared.INVALID && mExpandedMediaSetIndex < mMediaSets.size()) {
819f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            return mMediaSets.get(mExpandedMediaSetIndex);
820f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
821f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return null;
822f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
823f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
824f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void performClustering() {
825f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mListener != null) {
826f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mListener.onFeedAboutToChange(this);
827f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
828f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        MediaSet setToUse = null;
8292a6f302015b435941369d94f04f3018972558c46Venkat Krishnaraj        if (mExpandedMediaSetIndex != Shared.INVALID && mExpandedMediaSetIndex < mMediaSets.size()) {
830f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            setToUse = mMediaSets.get(mExpandedMediaSetIndex);
831f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
832f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (setToUse != null) {
833f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaClustering clustering = null;
834d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks            synchronized (mClusterSets) {
835f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                // Make sure the computation is completed to the end.
836f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                clustering = mClusterSets.get(setToUse);
837f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                if (clustering != null) {
838f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    clustering.compute(null, true);
839f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                } else {
840f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                    return;
841f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                }
842f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
843f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mInClusteringMode = true;
844f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            updateListener(true);
845f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
846f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
847f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
848f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void moveSetToFront(MediaSet mediaSet) {
849f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        ArrayList<MediaSet> mediaSets = mMediaSets;
850f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        int numSets = mediaSets.size();
851f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (numSets == 0) {
852f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            mediaSets.add(mediaSet);
853f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            return;
854f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
855f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        MediaSet setToFind = mediaSets.get(0);
856f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (setToFind == mediaSet) {
857f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            return;
858f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
859f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mediaSets.set(0, mediaSet);
860f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        int indexToSwapTill = -1;
861f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        for (int i = 1; i < numSets; ++i) {
862f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            MediaSet set = mediaSets.get(i);
863f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            if (set == mediaSet) {
864f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                mediaSets.set(i, setToFind);
865f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                indexToSwapTill = i;
866f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                break;
867f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
868f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
869f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (indexToSwapTill != Shared.INVALID) {
870f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            for (int i = indexToSwapTill; i > 1; --i) {
871f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                MediaSet setEnd = mediaSets.get(i);
872f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                MediaSet setPrev = mediaSets.get(i - 1);
873f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                mediaSets.set(i, setPrev);
874f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks                mediaSets.set(i - 1, setEnd);
875f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            }
876f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        }
877d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks        mMediaFeedNeedsToRun = true;
878f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
879f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
880f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public MediaSet replaceMediaSet(long setId, DataSource dataSource) {
8811c729acdafe147abda6b3479eafb17607f172780Venkat        Log.i(TAG, "Replacing media set " + setId);
8821b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj        final MediaSet set = getMediaSet(setId);
883db6a1a6960d791d6004694da52b747de58886634Venkat        if (set != null)
884db6a1a6960d791d6004694da52b747de58886634Venkat            set.refresh();
8851b329b810c628b43c86a574ec6d4ad4478f02d3cVenkat Krishnaraj        return set;
886f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
887d8a6d17db8aaef2ea06c78fe643f06601d8aec5dDave Sparks
888f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public void setSingleImageMode(boolean singleImageMode) {
889f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        mSingleImageMode = singleImageMode;
890f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
891f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
892f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public boolean isSingleImageMode() {
893f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return mSingleImageMode;
894f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
895f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks
896f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    public MediaSet getExpandedMediaSet() {
897f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mExpandedMediaSetIndex == Shared.INVALID)
898f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            return null;
899f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        if (mExpandedMediaSetIndex >= mMediaSets.size())
900f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks            return null;
901f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks        return mMediaSets.get(mExpandedMediaSetIndex);
902f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks    }
9035e0474e8e1942c41234eb251f948c2fbb7445b02Venkat Krishnaraj
9045e0474e8e1942c41234eb251f948c2fbb7445b02Venkat Krishnaraj    public void refresh() {
90562dd11281ef6e12049dd6798b184157e9583d7d4Venkat        if (mDataSource != null) {
90662dd11281ef6e12049dd6798b184157e9583d7d4Venkat            synchronized (mRequestedRefresh) {
90762dd11281ef6e12049dd6798b184157e9583d7d4Venkat                mRequestedRefresh.add(mDataSource.getDatabaseUris());
90862dd11281ef6e12049dd6798b184157e9583d7d4Venkat            }
90962dd11281ef6e12049dd6798b184157e9583d7d4Venkat        }
910897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj    }
911897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj
912897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj    private void refresh(final String[] databaseUris) {
91362f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat        synchronized (mMediaSets) {
91462f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat            if (mDataSource != null) {
91562dd11281ef6e12049dd6798b184157e9583d7d4Venkat                synchronized (mRequestedRefresh) {
91662dd11281ef6e12049dd6798b184157e9583d7d4Venkat                    mRequestedRefresh.add(databaseUris);
91762dd11281ef6e12049dd6798b184157e9583d7d4Venkat                }
91862f6a6a2e299c0706bfd0d4a0bca0ef1b10d3f37Venkat            }
9195e0474e8e1942c41234eb251f948c2fbb7445b02Venkat Krishnaraj        }
9205e0474e8e1942c41234eb251f948c2fbb7445b02Venkat Krishnaraj    }
921897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj
922897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj    public void onPause() {
923897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj        final HashMap<String, ContentObserver> observers = mContentObservers;
9241b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat        final int numObservers = observers.size();
9251b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat        if (numObservers > 0) {
9261b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat            String[] uris = new String[numObservers];
9271b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat            final Set<String> keySet = observers.keySet();
9281b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat            if (keySet != null) {
9291b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                uris = keySet.toArray(uris);
9301b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                final int numUris = uris.length;
9311b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                final ContentResolver cr = mContext.getContentResolver();
9321b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                for (int i = 0; i < numUris; ++i) {
9331b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                    final String uri = uris[i];
9341b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                    if (uri != null) {
9351b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                        final ContentObserver observer = observers.get(uri);
9361b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                        cr.unregisterContentObserver(observer);
9371b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                        observers.remove(uri);
9381b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                    }
9391b2ccb78ad045ad14f4f18e218003bf317e7c85eVenkat                }
940897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj            }
941897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj        }
942897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj        observers.clear();
943897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj    }
944897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj
945897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj    public void onResume() {
9465a626da1e8c21ee7c9e5f4d8142fc5adf7252f10Venkat        final Context context = mContext;
9475a626da1e8c21ee7c9e5f4d8142fc5adf7252f10Venkat        final DataSource dataSource = mDataSource;
9485a626da1e8c21ee7c9e5f4d8142fc5adf7252f10Venkat        if (context == null || dataSource == null)
9495a626da1e8c21ee7c9e5f4d8142fc5adf7252f10Venkat            return;
950897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj        // We setup the listeners for this datasource
9515a626da1e8c21ee7c9e5f4d8142fc5adf7252f10Venkat        final String[] uris = dataSource.getDatabaseUris();
952897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj        final HashMap<String, ContentObserver> observers = mContentObservers;
9535a626da1e8c21ee7c9e5f4d8142fc5adf7252f10Venkat        if (context instanceof Gallery) {
9545a626da1e8c21ee7c9e5f4d8142fc5adf7252f10Venkat            final Gallery gallery = (Gallery) context;
9555a626da1e8c21ee7c9e5f4d8142fc5adf7252f10Venkat            final ContentResolver cr = context.getContentResolver();
956897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj            if (uris != null) {
957897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                final int numUris = uris.length;
958897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                for (int i = 0; i < numUris; ++i) {
959897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                    final String uri = uris[i];
960897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                    final ContentObserver presentObserver = observers.get(uri);
961897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                    if (presentObserver == null) {
9625a626da1e8c21ee7c9e5f4d8142fc5adf7252f10Venkat                        final Handler handler = App.get(context).getHandler();
963897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                        final ContentObserver observer = new ContentObserver(handler) {
964897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                            public void onChange(boolean selfChange) {
965897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                                if (!mWaitingForMediaScanner) {
966897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                                    MediaFeed.this.refresh(new String[] { uri });
967897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                                }
968897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                            }
969897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                        };
97062dd11281ef6e12049dd6798b184157e9583d7d4Venkat                        cr.registerContentObserver(Uri.parse(uri), true, observer);
971897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                        observers.put(uri, observer);
972897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                    }
973897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj                }
974897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj            }
975897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj        }
976897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj        refresh();
977897ad622181117e8acbdeae2ff0afece68f1332cVenkat Krishnaraj    }
978f99dfe8549fb6c2c06c8cb7ca7d5eb33002c809eDave Sparks}
979