RemoteViewsAdapter.java revision fbc3590f40436e372df198c2d6b27877ae8952f1
1499cb9f516062b654952d282f211bee44c31a3c2Winson Chung/*
2499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * Copyright (C) 2007 The Android Open Source Project
3499cb9f516062b654952d282f211bee44c31a3c2Winson Chung *
4499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * Licensed under the Apache License, Version 2.0 (the "License");
5499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * you may not use this file except in compliance with the License.
6499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * You may obtain a copy of the License at
7499cb9f516062b654952d282f211bee44c31a3c2Winson Chung *
8499cb9f516062b654952d282f211bee44c31a3c2Winson Chung *      http://www.apache.org/licenses/LICENSE-2.0
9499cb9f516062b654952d282f211bee44c31a3c2Winson Chung *
10499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * Unless required by applicable law or agreed to in writing, software
11499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * distributed under the License is distributed on an "AS IS" BASIS,
12499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * See the License for the specific language governing permissions and
14499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * limitations under the License.
15499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */
16499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
17499cb9f516062b654952d282f211bee44c31a3c2Winson Chungpackage android.widget;
18499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
19499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport java.util.HashMap;
20c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chungimport java.util.LinkedList;
21499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport java.util.Map;
22499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
23499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.content.ComponentName;
24499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.content.Context;
25499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.content.Intent;
26499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.content.ServiceConnection;
27499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.graphics.Color;
28499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.os.Handler;
29499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.os.HandlerThread;
30499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.os.IBinder;
31499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.os.Looper;
32fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chungimport android.util.Log;
33499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.view.Gravity;
34499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.view.View;
35499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.view.ViewGroup;
36499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.view.View.MeasureSpec;
37499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
38499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport com.android.internal.widget.IRemoteViewsFactory;
39499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
40499cb9f516062b654952d282f211bee44c31a3c2Winson Chung/**
41499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * An adapter to a RemoteViewsService which fetches and caches RemoteViews
42499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * to be later inflated as child views.
43499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */
44499cb9f516062b654952d282f211bee44c31a3c2Winson Chung/** @hide */
45499cb9f516062b654952d282f211bee44c31a3c2Winson Chungpublic class RemoteViewsAdapter extends BaseAdapter {
46fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung    private static final String TAG = "RemoteViewsAdapter";
47499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
48499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private Context mContext;
49499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private Intent mIntent;
50499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private RemoteViewsAdapterServiceConnection mServiceConnection;
51499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private RemoteViewsCache mViewCache;
52499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
53499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private HandlerThread mWorkerThread;
54499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    // items may be interrupted within the normally processed queues
55499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private Handler mWorkerQueue;
56499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private Handler mMainQueue;
57499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    // items are never dequeued from the priority queue and must run
58499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private Handler mWorkerPriorityQueue;
59499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private Handler mMainPriorityQueue;
60499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
61499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
62499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * An interface for the RemoteAdapter to notify other classes when adapters
63499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * are actually connected to/disconnected from their actual services.
64499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
65499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public interface RemoteAdapterConnectionCallback {
66499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public void onRemoteAdapterConnected();
67499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
68499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public void onRemoteAdapterDisconnected();
69499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
70499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
71499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
72499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * The service connection that gets populated when the RemoteViewsService is
73499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * bound.
74499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
75499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private class RemoteViewsAdapterServiceConnection implements ServiceConnection {
76499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private boolean mConnected;
77499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private IRemoteViewsFactory mRemoteViewsFactory;
78499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private RemoteAdapterConnectionCallback mCallback;
79499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
80499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public RemoteViewsAdapterServiceConnection(RemoteAdapterConnectionCallback callback) {
81499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mCallback = callback;
82499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
83499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
84499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public void onServiceConnected(ComponentName name, IBinder service) {
85499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mRemoteViewsFactory = IRemoteViewsFactory.Stub.asInterface(service);
86499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mConnected = true;
87c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung
88499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // notifyDataSetChanged should be called first, to ensure that the
89499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // views are not updated twice
90499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            notifyDataSetChanged();
91499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
92499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // post a new runnable to load the appropriate data, then callback
93499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mWorkerPriorityQueue.post(new Runnable() {
94499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                @Override
95499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                public void run() {
96499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // we need to get the viewTypeCount specifically, so just get all the
97499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // metadata
98499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    mViewCache.requestMetaData();
99499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
100499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // post a runnable to call the callback on the main thread
101499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    mMainPriorityQueue.post(new Runnable() {
102499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        @Override
103499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        public void run() {
104499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            if (mCallback != null)
105499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                mCallback.onRemoteAdapterConnected();
106499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        }
107499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    });
108499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
109499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            });
1103ad4a1b13f789757a46dc0aea98c97b9fdc5ef6cAdam Cohen
1113ad4a1b13f789757a46dc0aea98c97b9fdc5ef6cAdam Cohen            // start the background loader
1123ad4a1b13f789757a46dc0aea98c97b9fdc5ef6cAdam Cohen            mViewCache.startBackgroundLoader();
113499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
114499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
115499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public void onServiceDisconnected(ComponentName name) {
116499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mRemoteViewsFactory = null;
117499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mConnected = false;
118499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
119499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // clear the main/worker queues
120499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mMainQueue.removeMessages(0);
121c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung
122c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            // stop the background loader
123c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            mViewCache.stopBackgroundLoader();
124c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung
125c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            if (mCallback != null)
126c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                mCallback.onRemoteAdapterDisconnected();
127499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
128499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
129499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public IRemoteViewsFactory getRemoteViewsFactory() {
130499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return mRemoteViewsFactory;
131499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
132499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
133499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public boolean isConnected() {
134499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return mConnected;
135499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
136499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
137499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
138499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    /**
139499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     * An internal cache of remote views.
140499cb9f516062b654952d282f211bee44c31a3c2Winson Chung     */
141499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private class RemoteViewsCache {
142fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung        private static final String TAG = "RemoteViewsCache";
143fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung
144499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private RemoteViewsInfo mViewCacheInfo;
145499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private RemoteViewsIndexInfo[] mViewCache;
146c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung        private int[] mTmpViewCacheLoadIndices;
147c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung        private LinkedList<Integer> mViewCacheLoadIndices;
148c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung        private boolean mBackgroundLoaderEnabled;
149499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
150499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        // if a user loading view is not provided, then we create a temporary one
151499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        // for the user using the height of the first view
152499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private RemoteViews mUserLoadingView;
153499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private RemoteViews mFirstView;
154499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private int mFirstViewHeight;
155499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
156499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        // determines when the current cache window needs to be updated with new
157499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        // items (ie. when there is not enough slack)
158499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private int mViewCacheStartPosition;
159499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private int mViewCacheEndPosition;
160499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private int mHalfCacheSize;
161499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private int mCacheSlack;
162499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private final float mCacheSlackPercentage = 0.75f;
163499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
164499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        /**
165499cb9f516062b654952d282f211bee44c31a3c2Winson Chung         * The data structure stored at each index of the cache. Any member
166499cb9f516062b654952d282f211bee44c31a3c2Winson Chung         * that is not invalidated persists throughout the lifetime of the cache.
167499cb9f516062b654952d282f211bee44c31a3c2Winson Chung         */
168499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private class RemoteViewsIndexInfo {
169499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            FrameLayout flipper;
170499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            RemoteViews view;
171499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            long itemId;
172499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            int typeId;
173499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
174499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            RemoteViewsIndexInfo() {
175499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                invalidate();
176499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
177499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
178499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            void set(RemoteViews v, long id) {
179499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                view = v;
180499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                itemId = id;
181499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                if (v != null)
182499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    typeId = v.getLayoutId();
183499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                else
184499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    typeId = 0;
185499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
186499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
187499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            void invalidate() {
188499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                view = null;
189499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                itemId = 0;
190499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                typeId = 0;
191499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
192499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
193499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            final boolean isValid() {
194499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                return (view != null);
195499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
196499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
197499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
198499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        /**
199499cb9f516062b654952d282f211bee44c31a3c2Winson Chung         * Remote adapter metadata. Useful for when we have to lock on something
200499cb9f516062b654952d282f211bee44c31a3c2Winson Chung         * before updating the metadata.
201499cb9f516062b654952d282f211bee44c31a3c2Winson Chung         */
202499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private class RemoteViewsInfo {
203499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            int count;
204499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            int viewTypeCount;
205499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            boolean hasStableIds;
2066394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            boolean isDataDirty;
207499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            Map<Integer, Integer> mTypeIdIndexMap;
208499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
209499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            RemoteViewsInfo() {
210499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                count = 0;
211499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                // by default there is at least one dummy view type
212499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                viewTypeCount = 1;
213499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                hasStableIds = true;
2146394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                isDataDirty = false;
215499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                mTypeIdIndexMap = new HashMap<Integer, Integer>();
216499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
217499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
218499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
219499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public RemoteViewsCache(int halfCacheSize) {
220499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mHalfCacheSize = halfCacheSize;
221499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mCacheSlack = Math.round(mCacheSlackPercentage * mHalfCacheSize);
222499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mViewCacheStartPosition = 0;
223499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mViewCacheEndPosition = -1;
224c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            mBackgroundLoaderEnabled = false;
225499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
226499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // initialize the cache
227c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            int cacheSize = 2 * mHalfCacheSize + 1;
228499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mViewCacheInfo = new RemoteViewsInfo();
229c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            mViewCache = new RemoteViewsIndexInfo[cacheSize];
230499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            for (int i = 0; i < mViewCache.length; ++i) {
231499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                mViewCache[i] = new RemoteViewsIndexInfo();
232499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
233c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            mTmpViewCacheLoadIndices = new int[cacheSize];
234c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            mViewCacheLoadIndices = new LinkedList<Integer>();
235499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
236499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
237499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private final boolean contains(int position) {
238c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            return (mViewCacheStartPosition <= position) && (position <= mViewCacheEndPosition);
239499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
240499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
241499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private final boolean containsAndIsValid(int position) {
242499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            if (contains(position)) {
243499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                RemoteViewsIndexInfo indexInfo = mViewCache[getCacheIndex(position)];
244499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                if (indexInfo.isValid()) {
245499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    return true;
246499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
247499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
248499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return false;
249499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
250499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
251499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private final int getCacheIndex(int position) {
252c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            // take the modulo of the position
253fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung            final int cacheSize = mViewCache.length;
254fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung            return (cacheSize + (position % cacheSize)) % cacheSize;
255499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
256499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
257499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public void requestMetaData() {
258499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            if (mServiceConnection.isConnected()) {
259499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                try {
260499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
261499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
262499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // get the properties/first view (so that we can use it to
263499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // measure our dummy views)
264499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    boolean hasStableIds = factory.hasStableIds();
265499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    int viewTypeCount = factory.getViewTypeCount();
266499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    int count = factory.getCount();
267499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    RemoteViews loadingView = factory.getLoadingView();
268499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    RemoteViews firstView = null;
269499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    if ((count > 0) && (loadingView == null)) {
270499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        firstView = factory.getViewAt(0);
271499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    }
272499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    synchronized (mViewCacheInfo) {
273499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        RemoteViewsInfo info = mViewCacheInfo;
274499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        info.hasStableIds = hasStableIds;
275499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        info.viewTypeCount = viewTypeCount + 1;
276499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        info.count = count;
277499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        mUserLoadingView = loadingView;
278499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        if (firstView != null) {
279499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            mFirstView = firstView;
280499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            mFirstViewHeight = -1;
281499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        }
282499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    }
283fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                } catch (Exception e) {
284fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    // print the error
285fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    Log.e(TAG, "Error in requestMetaData(): " + e.getMessage());
286fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung
287fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    // reset any members after the failed call
288fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    synchronized (mViewCacheInfo) {
289fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                        RemoteViewsInfo info = mViewCacheInfo;
290fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                        info.hasStableIds = false;
291fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                        info.viewTypeCount = 1;
292fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                        info.count = 0;
293fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                        mUserLoadingView = null;
294fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                        mFirstView = null;
295fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                        mFirstViewHeight = -1;
296fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    }
297499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
298499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
299499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
300499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
3016394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        protected void onNotifyDataSetChanged() {
3026394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            // we mark the data as dirty so that the next call to fetch views will result in
3036394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            // an onDataSetDirty() call from the adapter
3046394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            synchronized (mViewCacheInfo) {
3056394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                mViewCacheInfo.isDataDirty = true;
3066394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            }
3076394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        }
3086394c0e52cf641d93f678fd052499aa952e3595dWinson Chung
3096394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        private void updateNotifyDataSetChanged() {
3106394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            // actually calls through to the factory to notify it to update
3116394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            if (mServiceConnection.isConnected()) {
3126394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
3136394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                try {
314fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    // call back to the factory
3156394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                    factory.onDataSetChanged();
316fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                } catch (Exception e) {
317fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    // print the error
318fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    Log.e(TAG, "Error in updateNotifyDataSetChanged(): " + e.getMessage());
3196394c0e52cf641d93f678fd052499aa952e3595dWinson Chung
320fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    // return early to prevent container from being notified (nothing has changed)
321fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    return;
322fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                }
3236394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            }
3246394c0e52cf641d93f678fd052499aa952e3595dWinson Chung
3256394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            // re-request the new metadata (only after the notification to the factory)
3266394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            requestMetaData();
3276394c0e52cf641d93f678fd052499aa952e3595dWinson Chung
3286394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            // post a new runnable on the main thread to propagate the notification back
3296394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            // to the base adapter
3306394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            mMainQueue.post(new Runnable() {
3316394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                @Override
3326394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                public void run() {
3336394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                   completeNotifyDataSetChanged();
3346394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                }
3356394c0e52cf641d93f678fd052499aa952e3595dWinson Chung            });
3366394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        }
3376394c0e52cf641d93f678fd052499aa952e3595dWinson Chung
338499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        protected void updateRemoteViewsInfo(int position) {
339499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            if (mServiceConnection.isConnected()) {
340499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory();
341499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
342499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                // load the item information
343499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                RemoteViews remoteView = null;
344499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                long itemId = 0;
345499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                try {
346499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    remoteView = factory.getViewAt(position);
347499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    itemId = factory.getItemId(position);
348fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                } catch (Exception e) {
349fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    // print the error
350fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    Log.e(TAG, "Error in updateRemoteViewsInfo(" + position + "): " +
351fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                            e.getMessage());
352499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    e.printStackTrace();
353fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung
354fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    // return early to prevent additional work in re-centering the view cache, and
355fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    // swapping from the loading view
356fbc3590f40436e372df198c2d6b27877ae8952f1Winson Chung                    return;
357499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
358499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
359499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                synchronized (mViewCache) {
360499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // skip if the window has moved
361c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    if (position < mViewCacheStartPosition || position > mViewCacheEndPosition)
362499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        return;
363499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
364499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    final int positionIndex = position;
365499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    final int cacheIndex = getCacheIndex(position);
366499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    mViewCache[cacheIndex].set(remoteView, itemId);
367499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
368499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // notify the main thread when done loading
369499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // flush pending updates
370499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    mMainQueue.post(new Runnable() {
371499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        @Override
372499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        public void run() {
373499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            // swap the loader view for this view
374499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            synchronized (mViewCache) {
375499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                if (containsAndIsValid(positionIndex)) {
376499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                    RemoteViewsIndexInfo indexInfo = mViewCache[cacheIndex];
377499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                    FrameLayout flipper = indexInfo.flipper;
378499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
379c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                    // update the flipper
380c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                    flipper.getChildAt(0).setVisibility(View.GONE);
381c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                    boolean addNewView = true;
382c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                    if (flipper.getChildCount() > 1) {
383c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                        View v = flipper.getChildAt(1);
384c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                        int typeId = ((Integer) v.getTag()).intValue();
385c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                        if (typeId == indexInfo.typeId) {
386c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                            // we can reapply since it is the same type
387c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                            indexInfo.view.reapply(mContext, v);
388c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                            v.setVisibility(View.VISIBLE);
389c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                            if (v.getAnimation() != null)
390c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                                v.buildDrawingCache();
391c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                            addNewView = false;
392c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                        } else {
393c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                            flipper.removeViewAt(1);
394c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                        }
395c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                    }
396c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                    if (addNewView) {
397c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                        View v = indexInfo.view.apply(mContext, flipper);
398c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                        v.setTag(new Integer(indexInfo.typeId));
399c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                        flipper.addView(v);
400c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                    }
401499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                }
402499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            }
403499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        }
404499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    });
405499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
406499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
407499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
408499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
409499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        private RemoteViewsIndexInfo requestCachedIndexInfo(final int position) {
410499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            int indicesToLoadCount = 0;
411499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
412499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            synchronized (mViewCache) {
413499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                if (containsAndIsValid(position)) {
414499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // return the info if it exists in the window and is loaded
415499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    return mViewCache[getCacheIndex(position)];
416c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                }
417499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
418499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                // if necessary update the window and load the new information
419499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                int centerPosition = (mViewCacheEndPosition + mViewCacheStartPosition) / 2;
420499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                if ((mViewCacheEndPosition <= mViewCacheStartPosition) || (Math.abs(position - centerPosition) > mCacheSlack)) {
421499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    int newStartPosition = position - mHalfCacheSize;
422499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    int newEndPosition = position + mHalfCacheSize;
423c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    int frameSize = mHalfCacheSize / 4;
424c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    int frameCount = (int) Math.ceil(mViewCache.length / (float) frameSize);
425499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
426499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // prune/add before the current start position
427499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    int effectiveStart = Math.max(newStartPosition, 0);
428c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    int effectiveEnd = Math.min(newEndPosition, getCount() - 1);
429499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
430499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // invalidate items in the queue
431499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    int overlapStart = Math.max(mViewCacheStartPosition, effectiveStart);
432499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    int overlapEnd = Math.min(Math.max(mViewCacheStartPosition, mViewCacheEndPosition), effectiveEnd);
433c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    for (int i = 0; i < (frameSize * frameCount); ++i) {
434c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                        int index = newStartPosition + ((i % frameSize) * frameCount + (i / frameSize));
435c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung
436c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                        if (index <= newEndPosition) {
437c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            if ((overlapStart <= index) && (index <= overlapEnd)) {
438c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                // load the stuff in the middle that has not already
439c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                // been loaded
440c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                if (!mViewCache[getCacheIndex(index)].isValid()) {
441c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                    mTmpViewCacheLoadIndices[indicesToLoadCount++] = index;
442c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                }
443c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            } else if ((effectiveStart <= index) && (index <= effectiveEnd)) {
444c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                // invalidate and load all new effective items
445c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                mViewCache[getCacheIndex(index)].invalidate();
446c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                mTmpViewCacheLoadIndices[indicesToLoadCount++] = index;
447c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            } else {
448c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                // invalidate all other cache indices (outside the effective start/end)
449c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                // but don't load
450c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                mViewCache[getCacheIndex(index)].invalidate();
451499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            }
452499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        }
453499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    }
454499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
455499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    mViewCacheStartPosition = newStartPosition;
456499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    mViewCacheEndPosition = newEndPosition;
457499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
458499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
459499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
460499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // post items to be loaded
461499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            int length = 0;
462499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            synchronized (mViewCacheInfo) {
463499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                length = mViewCacheInfo.count;
464499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
465c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            if (indicesToLoadCount > 0) {
466c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                synchronized (mViewCacheLoadIndices) {
467c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    mViewCacheLoadIndices.clear();
468c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    for (int i = 0; i < indicesToLoadCount; ++i) {
469c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                        final int index = mTmpViewCacheLoadIndices[i];
470c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                        if (0 <= index && index < length) {
471c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            mViewCacheLoadIndices.addLast(index);
472499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        }
473c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    }
474499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
475499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
476499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
477499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // return null so that a dummy view can be retrieved
478499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return null;
479499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
480499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
481499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public View getView(int position, View convertView, ViewGroup parent) {
482499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            if (mServiceConnection.isConnected()) {
483499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                // create the flipper views if necessary (we have to do this now
484499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                // for all the flippers while we have the reference to the parent)
485c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                initializeLoadingViews(parent);
486499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
487499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                // request the item from the cache (queueing it to load if not
488499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                // in the cache already)
489499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                RemoteViewsIndexInfo indexInfo = requestCachedIndexInfo(position);
490499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
491499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                // update the flipper appropriately
492499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                synchronized (mViewCache) {
493499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    int cacheIndex = getCacheIndex(position);
494499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    FrameLayout flipper = mViewCache[cacheIndex].flipper;
495c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    flipper.setVisibility(View.VISIBLE);
49644729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen                    flipper.setAlpha(1.0f);
497499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
498499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    if (indexInfo == null) {
499499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        // hide the item view and show the loading view
500499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        flipper.getChildAt(0).setVisibility(View.VISIBLE);
501499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        for (int i = 1; i < flipper.getChildCount(); ++i) {
502499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            flipper.getChildAt(i).setVisibility(View.GONE);
503499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        }
504499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    } else {
505499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        // hide the loading view and show the item view
506499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        for (int i = 0; i < flipper.getChildCount() - 1; ++i) {
507499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            flipper.getChildAt(i).setVisibility(View.GONE);
508499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        }
509499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        flipper.getChildAt(flipper.getChildCount() - 1).setVisibility(View.VISIBLE);
510499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    }
511499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    return flipper;
512499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
513499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
514499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return new View(mContext);
515499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
516499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
517c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung        private void initializeLoadingViews(ViewGroup parent) {
518499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // ensure that the cache has the appropriate initial flipper
519499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            synchronized (mViewCache) {
520499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                if (mViewCache[0].flipper == null) {
521499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    for (int i = 0; i < mViewCache.length; ++i) {
522499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        FrameLayout flipper = new FrameLayout(mContext);
523499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        if (mUserLoadingView != null) {
524499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            // use the user-specified loading view
525499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            flipper.addView(mUserLoadingView.apply(mContext, parent));
526499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        } else {
527499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            // calculate the original size of the first row for the loader view
528499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            synchronized (mViewCacheInfo) {
529499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                if (mFirstViewHeight < 0) {
530499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                    View firstView = mFirstView.apply(mContext, parent);
531499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                    firstView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
532499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                            MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
533499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                    mFirstViewHeight = firstView.getMeasuredHeight();
534499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                                }
535499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            }
536499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
537499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            // construct a new loader and add it to the flipper as the fallback
538499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            // default view
539499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            TextView textView = new TextView(mContext);
540499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            textView.setText("Loading...");
541499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            textView.setHeight(mFirstViewHeight);
542499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            textView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
543499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            textView.setTextSize(18.0f);
544499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            textView.setTextColor(Color.argb(96, 255, 255, 255));
545499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            textView.setShadowLayer(2.0f, 0.0f, 1.0f, Color.BLACK);
546499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
547499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                            flipper.addView(textView);
548499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        }
549499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        mViewCache[i].flipper = flipper;
550499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    }
551499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
552499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
553499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
554499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
555c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung        public void startBackgroundLoader() {
556c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            // initialize the worker runnable
557c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            mBackgroundLoaderEnabled = true;
558c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            mWorkerQueue.post(new Runnable() {
559c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                @Override
560c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                public void run() {
561c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    while (mBackgroundLoaderEnabled) {
5626394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                        // notify the RemoteViews factory if necessary
5636394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                        boolean isDataDirty = false;
5646394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                        synchronized (mViewCacheInfo) {
5656394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                            isDataDirty = mViewCacheInfo.isDataDirty;
5666394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                            mViewCacheInfo.isDataDirty = false;
5676394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                        }
5686394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                        if (isDataDirty) {
5696394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                            updateNotifyDataSetChanged();
5706394c0e52cf641d93f678fd052499aa952e3595dWinson Chung                        }
5716394c0e52cf641d93f678fd052499aa952e3595dWinson Chung
572c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                        int index = -1;
573c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                        synchronized (mViewCacheLoadIndices) {
574c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            if (!mViewCacheLoadIndices.isEmpty()) {
575c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                index = mViewCacheLoadIndices.removeFirst();
576c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            }
577c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                        }
578c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                        if (index < 0) {
579c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            // there were no items to load, so sleep for a bit
580c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            try {
581c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                Thread.sleep(10);
582c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            } catch (InterruptedException e) {
583c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                                e.printStackTrace();
584c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            }
585c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                        } else {
586c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            // otherwise, try and load the item
587c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                            updateRemoteViewsInfo(index);
588c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                        }
589c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                    }
590c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                }
591c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            });
592c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung        }
593c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung
594c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung        public void stopBackgroundLoader() {
595c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            // clear the items to be loaded
596c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            mBackgroundLoaderEnabled = false;
597c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            synchronized (mViewCacheLoadIndices) {
598c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                mViewCacheLoadIndices.clear();
599c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            }
600c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung        }
601c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung
602499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public long getItemId(int position) {
603499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            synchronized (mViewCache) {
604499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                if (containsAndIsValid(position)) {
605499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    return mViewCache[getCacheIndex(position)].itemId;
606499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
607499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
608499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return 0;
609499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
610499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
611499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public int getItemViewType(int position) {
612499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // synchronize to ensure that the type id/index map is updated synchronously
613499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            synchronized (mViewCache) {
614499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                if (containsAndIsValid(position)) {
615499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    int viewId = mViewCache[getCacheIndex(position)].typeId;
616499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    Map<Integer, Integer> typeMap = mViewCacheInfo.mTypeIdIndexMap;
617499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    // we +1 because the default dummy view get view type 0
618499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    if (typeMap.containsKey(viewId)) {
619499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        return typeMap.get(viewId);
620499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    } else {
621499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        int newIndex = typeMap.size() + 1;
622499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        typeMap.put(viewId, newIndex);
623499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                        return newIndex;
624499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    }
625499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
626499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
627499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            // return the type of the default item
628499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            return 0;
629499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
630499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
631499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public int getCount() {
632499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            synchronized (mViewCacheInfo) {
633499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                return mViewCacheInfo.count;
634499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
635499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
636499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
637499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public int getViewTypeCount() {
638499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            synchronized (mViewCacheInfo) {
639499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                return mViewCacheInfo.viewTypeCount;
640499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
641499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
642499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
643499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public boolean hasStableIds() {
644499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            synchronized (mViewCacheInfo) {
645499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                return mViewCacheInfo.hasStableIds;
646499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
647499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
648499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
649499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        public void flushCache() {
650c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            // clear the items to be loaded
651c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            synchronized (mViewCacheLoadIndices) {
652c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung                mViewCacheLoadIndices.clear();
653c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung            }
654c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung
655499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            synchronized (mViewCache) {
656499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                // flush the internal cache and invalidate the adapter for future loads
657499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                mMainQueue.removeMessages(0);
658499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
659499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                for (int i = 0; i < mViewCache.length; ++i) {
660499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                    mViewCache[i].invalidate();
661499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                }
662499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
663499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                mViewCacheStartPosition = 0;
664499cb9f516062b654952d282f211bee44c31a3c2Winson Chung                mViewCacheEndPosition = -1;
665499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            }
666499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
667499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
668499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
669499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public RemoteViewsAdapter(Context context, Intent intent, RemoteAdapterConnectionCallback callback) {
670499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mContext = context;
671499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mIntent = intent;
672499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
673499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        // initialize the worker thread
674499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mWorkerThread = new HandlerThread("RemoteViewsCache-loader");
675499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mWorkerThread.start();
676499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mWorkerQueue = new Handler(mWorkerThread.getLooper());
677499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mWorkerPriorityQueue = new Handler(mWorkerThread.getLooper());
678499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mMainQueue = new Handler(Looper.myLooper());
679499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mMainPriorityQueue = new Handler(Looper.myLooper());
680499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
681499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        // initialize the cache and the service connection on startup
682499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mViewCache = new RemoteViewsCache(25);
683499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mServiceConnection = new RemoteViewsAdapterServiceConnection(callback);
684499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        requestBindService();
685499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
686499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
687499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    protected void finalize() throws Throwable {
688499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        // remember to unbind from the service when finalizing
689499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        unbindService();
690499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
691499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
692499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public int getCount() {
693499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        requestBindService();
694499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        return mViewCache.getCount();
695499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
696499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
697499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public Object getItem(int position) {
698499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        // disallow arbitrary object to be associated with an item for the time being
699499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        return null;
700499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
701499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
702499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public long getItemId(int position) {
703499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        requestBindService();
704499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        return mViewCache.getItemId(position);
705499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
706499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
707499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public int getItemViewType(int position) {
708499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        requestBindService();
709499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        return mViewCache.getItemViewType(position);
710499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
711499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
712499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public View getView(int position, View convertView, ViewGroup parent) {
713499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        requestBindService();
714499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        return mViewCache.getView(position, convertView, parent);
715499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
716499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
717499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public int getViewTypeCount() {
718499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        requestBindService();
719499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        return mViewCache.getViewTypeCount();
720499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
721499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
722499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public boolean hasStableIds() {
723499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        requestBindService();
724499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        return mViewCache.hasStableIds();
725499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
726499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
727499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public boolean isEmpty() {
728499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        return getCount() <= 0;
729499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
730499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
731499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    public void notifyDataSetChanged() {
732499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        // flush the cache so that we can reload new items from the service
733499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        mViewCache.flushCache();
7346394c0e52cf641d93f678fd052499aa952e3595dWinson Chung
7356394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        // notify the factory that it's data may no longer be valid
7366394c0e52cf641d93f678fd052499aa952e3595dWinson Chung        mViewCache.onNotifyDataSetChanged();
7376394c0e52cf641d93f678fd052499aa952e3595dWinson Chung    }
7386394c0e52cf641d93f678fd052499aa952e3595dWinson Chung
7396394c0e52cf641d93f678fd052499aa952e3595dWinson Chung    public void completeNotifyDataSetChanged() {
740499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        super.notifyDataSetChanged();
741499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
742499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
743499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private boolean requestBindService() {
744499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        // try binding the service (which will start it if it's not already running)
745499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        if (!mServiceConnection.isConnected()) {
746499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
747499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
748499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
749499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        return mServiceConnection.isConnected();
750499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
751499cb9f516062b654952d282f211bee44c31a3c2Winson Chung
752499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    private void unbindService() {
753499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        if (mServiceConnection.isConnected()) {
754499cb9f516062b654952d282f211bee44c31a3c2Winson Chung            mContext.unbindService(mServiceConnection);
755499cb9f516062b654952d282f211bee44c31a3c2Winson Chung        }
756499cb9f516062b654952d282f211bee44c31a3c2Winson Chung    }
757499cb9f516062b654952d282f211bee44c31a3c2Winson Chung}
758