RemoteViewsAdapter.java revision 6394c0e52cf641d93f678fd052499aa952e3595d
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; 32499cb9f516062b654952d282f211bee44c31a3c2Winson Chungimport android.os.RemoteException; 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 { 46499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 47499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private static final String LOG_TAG = "RemoteViewsAdapter"; 48499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 49499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private Context mContext; 50499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private Intent mIntent; 51499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private RemoteViewsAdapterServiceConnection mServiceConnection; 52499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private RemoteViewsCache mViewCache; 53499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 54499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private HandlerThread mWorkerThread; 55499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // items may be interrupted within the normally processed queues 56499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private Handler mWorkerQueue; 57499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private Handler mMainQueue; 58499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // items are never dequeued from the priority queue and must run 59499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private Handler mWorkerPriorityQueue; 60499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private Handler mMainPriorityQueue; 61499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 62499cb9f516062b654952d282f211bee44c31a3c2Winson Chung /** 63499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * An interface for the RemoteAdapter to notify other classes when adapters 64499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * are actually connected to/disconnected from their actual services. 65499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */ 66499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public interface RemoteAdapterConnectionCallback { 67499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public void onRemoteAdapterConnected(); 68499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 69499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public void onRemoteAdapterDisconnected(); 70499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 71499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 72499cb9f516062b654952d282f211bee44c31a3c2Winson Chung /** 73499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * The service connection that gets populated when the RemoteViewsService is 74499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * bound. 75499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */ 76499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private class RemoteViewsAdapterServiceConnection implements ServiceConnection { 77499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private boolean mConnected; 78499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private IRemoteViewsFactory mRemoteViewsFactory; 79499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private RemoteAdapterConnectionCallback mCallback; 80499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 81499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public RemoteViewsAdapterServiceConnection(RemoteAdapterConnectionCallback callback) { 82499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mCallback = callback; 83499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 84499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 85499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public void onServiceConnected(ComponentName name, IBinder service) { 86499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mRemoteViewsFactory = IRemoteViewsFactory.Stub.asInterface(service); 87499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mConnected = true; 88c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung 89499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // notifyDataSetChanged should be called first, to ensure that the 90499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // views are not updated twice 91499cb9f516062b654952d282f211bee44c31a3c2Winson Chung notifyDataSetChanged(); 92499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 93499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // post a new runnable to load the appropriate data, then callback 94499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mWorkerPriorityQueue.post(new Runnable() { 95499cb9f516062b654952d282f211bee44c31a3c2Winson Chung @Override 96499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public void run() { 97499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // we need to get the viewTypeCount specifically, so just get all the 98499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // metadata 99499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCache.requestMetaData(); 100499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 101499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // post a runnable to call the callback on the main thread 102499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mMainPriorityQueue.post(new Runnable() { 103499cb9f516062b654952d282f211bee44c31a3c2Winson Chung @Override 104499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public void run() { 105499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (mCallback != null) 106499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mCallback.onRemoteAdapterConnected(); 107499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 108499cb9f516062b654952d282f211bee44c31a3c2Winson Chung }); 109499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 110499cb9f516062b654952d282f211bee44c31a3c2Winson Chung }); 1113ad4a1b13f789757a46dc0aea98c97b9fdc5ef6cAdam Cohen 1123ad4a1b13f789757a46dc0aea98c97b9fdc5ef6cAdam Cohen // start the background loader 1133ad4a1b13f789757a46dc0aea98c97b9fdc5ef6cAdam Cohen mViewCache.startBackgroundLoader(); 114499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 115499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 116499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public void onServiceDisconnected(ComponentName name) { 117499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mRemoteViewsFactory = null; 118499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mConnected = false; 119499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 120499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // clear the main/worker queues 121499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mMainQueue.removeMessages(0); 122c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung 123c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // stop the background loader 124c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mViewCache.stopBackgroundLoader(); 125c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung 126c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (mCallback != null) 127c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mCallback.onRemoteAdapterDisconnected(); 128499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 129499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 130499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public IRemoteViewsFactory getRemoteViewsFactory() { 131499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mRemoteViewsFactory; 132499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 133499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 134499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public boolean isConnected() { 135499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mConnected; 136499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 137499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 138499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 139499cb9f516062b654952d282f211bee44c31a3c2Winson Chung /** 140499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * An internal cache of remote views. 141499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */ 142499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private class RemoteViewsCache { 143499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private RemoteViewsInfo mViewCacheInfo; 144499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private RemoteViewsIndexInfo[] mViewCache; 145c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung private int[] mTmpViewCacheLoadIndices; 146c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung private LinkedList<Integer> mViewCacheLoadIndices; 147c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung private boolean mBackgroundLoaderEnabled; 148499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 149499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // if a user loading view is not provided, then we create a temporary one 150499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // for the user using the height of the first view 151499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private RemoteViews mUserLoadingView; 152499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private RemoteViews mFirstView; 153499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private int mFirstViewHeight; 154499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 155499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // determines when the current cache window needs to be updated with new 156499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // items (ie. when there is not enough slack) 157499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private int mViewCacheStartPosition; 158499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private int mViewCacheEndPosition; 159499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private int mHalfCacheSize; 160499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private int mCacheSlack; 161499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private final float mCacheSlackPercentage = 0.75f; 162499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 163499cb9f516062b654952d282f211bee44c31a3c2Winson Chung /** 164499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * The data structure stored at each index of the cache. Any member 165499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * that is not invalidated persists throughout the lifetime of the cache. 166499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */ 167499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private class RemoteViewsIndexInfo { 168499cb9f516062b654952d282f211bee44c31a3c2Winson Chung FrameLayout flipper; 169499cb9f516062b654952d282f211bee44c31a3c2Winson Chung RemoteViews view; 170499cb9f516062b654952d282f211bee44c31a3c2Winson Chung long itemId; 171499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int typeId; 172499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 173499cb9f516062b654952d282f211bee44c31a3c2Winson Chung RemoteViewsIndexInfo() { 174499cb9f516062b654952d282f211bee44c31a3c2Winson Chung invalidate(); 175499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 176499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 177499cb9f516062b654952d282f211bee44c31a3c2Winson Chung void set(RemoteViews v, long id) { 178499cb9f516062b654952d282f211bee44c31a3c2Winson Chung view = v; 179499cb9f516062b654952d282f211bee44c31a3c2Winson Chung itemId = id; 180499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (v != null) 181499cb9f516062b654952d282f211bee44c31a3c2Winson Chung typeId = v.getLayoutId(); 182499cb9f516062b654952d282f211bee44c31a3c2Winson Chung else 183499cb9f516062b654952d282f211bee44c31a3c2Winson Chung typeId = 0; 184499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 185499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 186499cb9f516062b654952d282f211bee44c31a3c2Winson Chung void invalidate() { 187499cb9f516062b654952d282f211bee44c31a3c2Winson Chung view = null; 188499cb9f516062b654952d282f211bee44c31a3c2Winson Chung itemId = 0; 189499cb9f516062b654952d282f211bee44c31a3c2Winson Chung typeId = 0; 190499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 191499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 192499cb9f516062b654952d282f211bee44c31a3c2Winson Chung final boolean isValid() { 193499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return (view != null); 194499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 195499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 196499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 197499cb9f516062b654952d282f211bee44c31a3c2Winson Chung /** 198499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * Remote adapter metadata. Useful for when we have to lock on something 199499cb9f516062b654952d282f211bee44c31a3c2Winson Chung * before updating the metadata. 200499cb9f516062b654952d282f211bee44c31a3c2Winson Chung */ 201499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private class RemoteViewsInfo { 202499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int count; 203499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int viewTypeCount; 204499cb9f516062b654952d282f211bee44c31a3c2Winson Chung boolean hasStableIds; 2056394c0e52cf641d93f678fd052499aa952e3595dWinson Chung boolean isDataDirty; 206499cb9f516062b654952d282f211bee44c31a3c2Winson Chung Map<Integer, Integer> mTypeIdIndexMap; 207499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 208499cb9f516062b654952d282f211bee44c31a3c2Winson Chung RemoteViewsInfo() { 209499cb9f516062b654952d282f211bee44c31a3c2Winson Chung count = 0; 210499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // by default there is at least one dummy view type 211499cb9f516062b654952d282f211bee44c31a3c2Winson Chung viewTypeCount = 1; 212499cb9f516062b654952d282f211bee44c31a3c2Winson Chung hasStableIds = true; 2136394c0e52cf641d93f678fd052499aa952e3595dWinson Chung isDataDirty = false; 214499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mTypeIdIndexMap = new HashMap<Integer, Integer>(); 215499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 216499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 217499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 218499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public RemoteViewsCache(int halfCacheSize) { 219499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mHalfCacheSize = halfCacheSize; 220499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mCacheSlack = Math.round(mCacheSlackPercentage * mHalfCacheSize); 221499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCacheStartPosition = 0; 222499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCacheEndPosition = -1; 223c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mBackgroundLoaderEnabled = false; 224499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 225499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // initialize the cache 226c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung int cacheSize = 2 * mHalfCacheSize + 1; 227499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCacheInfo = new RemoteViewsInfo(); 228c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mViewCache = new RemoteViewsIndexInfo[cacheSize]; 229499cb9f516062b654952d282f211bee44c31a3c2Winson Chung for (int i = 0; i < mViewCache.length; ++i) { 230499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCache[i] = new RemoteViewsIndexInfo(); 231499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 232c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mTmpViewCacheLoadIndices = new int[cacheSize]; 233c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mViewCacheLoadIndices = new LinkedList<Integer>(); 234499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 235499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 236499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private final boolean contains(int position) { 237c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung return (mViewCacheStartPosition <= position) && (position <= mViewCacheEndPosition); 238499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 239499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 240499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private final boolean containsAndIsValid(int position) { 241499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (contains(position)) { 242499cb9f516062b654952d282f211bee44c31a3c2Winson Chung RemoteViewsIndexInfo indexInfo = mViewCache[getCacheIndex(position)]; 243499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (indexInfo.isValid()) { 244499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return true; 245499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 246499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 247499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return false; 248499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 249499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 250499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private final int getCacheIndex(int position) { 251c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // take the modulo of the position 252499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return (mViewCache.length + (position % mViewCache.length)) % mViewCache.length; 253499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 254499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 255499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public void requestMetaData() { 256499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (mServiceConnection.isConnected()) { 257499cb9f516062b654952d282f211bee44c31a3c2Winson Chung try { 258499cb9f516062b654952d282f211bee44c31a3c2Winson Chung IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory(); 259499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 260499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // get the properties/first view (so that we can use it to 261499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // measure our dummy views) 262499cb9f516062b654952d282f211bee44c31a3c2Winson Chung boolean hasStableIds = factory.hasStableIds(); 263499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int viewTypeCount = factory.getViewTypeCount(); 264499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int count = factory.getCount(); 265499cb9f516062b654952d282f211bee44c31a3c2Winson Chung RemoteViews loadingView = factory.getLoadingView(); 266499cb9f516062b654952d282f211bee44c31a3c2Winson Chung RemoteViews firstView = null; 267499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if ((count > 0) && (loadingView == null)) { 268499cb9f516062b654952d282f211bee44c31a3c2Winson Chung firstView = factory.getViewAt(0); 269499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 270499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCacheInfo) { 271499cb9f516062b654952d282f211bee44c31a3c2Winson Chung RemoteViewsInfo info = mViewCacheInfo; 272499cb9f516062b654952d282f211bee44c31a3c2Winson Chung info.hasStableIds = hasStableIds; 273499cb9f516062b654952d282f211bee44c31a3c2Winson Chung info.viewTypeCount = viewTypeCount + 1; 274499cb9f516062b654952d282f211bee44c31a3c2Winson Chung info.count = count; 275499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mUserLoadingView = loadingView; 276499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (firstView != null) { 277499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mFirstView = firstView; 278499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mFirstViewHeight = -1; 279499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 280499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 281499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } catch (RemoteException e) { 282499cb9f516062b654952d282f211bee44c31a3c2Winson Chung e.printStackTrace(); 283499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 284499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 285499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 286499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 2876394c0e52cf641d93f678fd052499aa952e3595dWinson Chung protected void onNotifyDataSetChanged() { 2886394c0e52cf641d93f678fd052499aa952e3595dWinson Chung // we mark the data as dirty so that the next call to fetch views will result in 2896394c0e52cf641d93f678fd052499aa952e3595dWinson Chung // an onDataSetDirty() call from the adapter 2906394c0e52cf641d93f678fd052499aa952e3595dWinson Chung synchronized (mViewCacheInfo) { 2916394c0e52cf641d93f678fd052499aa952e3595dWinson Chung mViewCacheInfo.isDataDirty = true; 2926394c0e52cf641d93f678fd052499aa952e3595dWinson Chung } 2936394c0e52cf641d93f678fd052499aa952e3595dWinson Chung } 2946394c0e52cf641d93f678fd052499aa952e3595dWinson Chung 2956394c0e52cf641d93f678fd052499aa952e3595dWinson Chung private void updateNotifyDataSetChanged() { 2966394c0e52cf641d93f678fd052499aa952e3595dWinson Chung // actually calls through to the factory to notify it to update 2976394c0e52cf641d93f678fd052499aa952e3595dWinson Chung if (mServiceConnection.isConnected()) { 2986394c0e52cf641d93f678fd052499aa952e3595dWinson Chung IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory(); 2996394c0e52cf641d93f678fd052499aa952e3595dWinson Chung try { 3006394c0e52cf641d93f678fd052499aa952e3595dWinson Chung factory.onDataSetChanged(); 3016394c0e52cf641d93f678fd052499aa952e3595dWinson Chung } catch (RemoteException e) { 3026394c0e52cf641d93f678fd052499aa952e3595dWinson Chung e.printStackTrace(); 3036394c0e52cf641d93f678fd052499aa952e3595dWinson Chung } 3046394c0e52cf641d93f678fd052499aa952e3595dWinson Chung 3056394c0e52cf641d93f678fd052499aa952e3595dWinson Chung } 3066394c0e52cf641d93f678fd052499aa952e3595dWinson Chung 3076394c0e52cf641d93f678fd052499aa952e3595dWinson Chung // re-request the new metadata (only after the notification to the factory) 3086394c0e52cf641d93f678fd052499aa952e3595dWinson Chung requestMetaData(); 3096394c0e52cf641d93f678fd052499aa952e3595dWinson Chung 3106394c0e52cf641d93f678fd052499aa952e3595dWinson Chung // post a new runnable on the main thread to propagate the notification back 3116394c0e52cf641d93f678fd052499aa952e3595dWinson Chung // to the base adapter 3126394c0e52cf641d93f678fd052499aa952e3595dWinson Chung mMainQueue.post(new Runnable() { 3136394c0e52cf641d93f678fd052499aa952e3595dWinson Chung @Override 3146394c0e52cf641d93f678fd052499aa952e3595dWinson Chung public void run() { 3156394c0e52cf641d93f678fd052499aa952e3595dWinson Chung completeNotifyDataSetChanged(); 3166394c0e52cf641d93f678fd052499aa952e3595dWinson Chung } 3176394c0e52cf641d93f678fd052499aa952e3595dWinson Chung }); 3186394c0e52cf641d93f678fd052499aa952e3595dWinson Chung } 3196394c0e52cf641d93f678fd052499aa952e3595dWinson Chung 320499cb9f516062b654952d282f211bee44c31a3c2Winson Chung protected void updateRemoteViewsInfo(int position) { 321499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (mServiceConnection.isConnected()) { 322499cb9f516062b654952d282f211bee44c31a3c2Winson Chung IRemoteViewsFactory factory = mServiceConnection.getRemoteViewsFactory(); 323499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 324499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // load the item information 325499cb9f516062b654952d282f211bee44c31a3c2Winson Chung RemoteViews remoteView = null; 326499cb9f516062b654952d282f211bee44c31a3c2Winson Chung long itemId = 0; 327499cb9f516062b654952d282f211bee44c31a3c2Winson Chung try { 328499cb9f516062b654952d282f211bee44c31a3c2Winson Chung remoteView = factory.getViewAt(position); 329499cb9f516062b654952d282f211bee44c31a3c2Winson Chung itemId = factory.getItemId(position); 330499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } catch (RemoteException e) { 331499cb9f516062b654952d282f211bee44c31a3c2Winson Chung e.printStackTrace(); 332499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 333499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 334499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCache) { 335499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // skip if the window has moved 336c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (position < mViewCacheStartPosition || position > mViewCacheEndPosition) 337499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return; 338499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 339499cb9f516062b654952d282f211bee44c31a3c2Winson Chung final int positionIndex = position; 340499cb9f516062b654952d282f211bee44c31a3c2Winson Chung final int cacheIndex = getCacheIndex(position); 341499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCache[cacheIndex].set(remoteView, itemId); 342499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 343499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // notify the main thread when done loading 344499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // flush pending updates 345499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mMainQueue.post(new Runnable() { 346499cb9f516062b654952d282f211bee44c31a3c2Winson Chung @Override 347499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public void run() { 348499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // swap the loader view for this view 349499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCache) { 350499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (containsAndIsValid(positionIndex)) { 351499cb9f516062b654952d282f211bee44c31a3c2Winson Chung RemoteViewsIndexInfo indexInfo = mViewCache[cacheIndex]; 352499cb9f516062b654952d282f211bee44c31a3c2Winson Chung FrameLayout flipper = indexInfo.flipper; 353499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 354c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // update the flipper 355c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung flipper.getChildAt(0).setVisibility(View.GONE); 356c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung boolean addNewView = true; 357c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (flipper.getChildCount() > 1) { 358c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung View v = flipper.getChildAt(1); 359c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung int typeId = ((Integer) v.getTag()).intValue(); 360c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (typeId == indexInfo.typeId) { 361c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // we can reapply since it is the same type 362c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung indexInfo.view.reapply(mContext, v); 363c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung v.setVisibility(View.VISIBLE); 364c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (v.getAnimation() != null) 365c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung v.buildDrawingCache(); 366c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung addNewView = false; 367c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } else { 368c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung flipper.removeViewAt(1); 369c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 370c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 371c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (addNewView) { 372c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung View v = indexInfo.view.apply(mContext, flipper); 373c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung v.setTag(new Integer(indexInfo.typeId)); 374c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung flipper.addView(v); 375c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 376499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 377499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 378499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 379499cb9f516062b654952d282f211bee44c31a3c2Winson Chung }); 380499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 381499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 382499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 383499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 384499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private RemoteViewsIndexInfo requestCachedIndexInfo(final int position) { 385499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int indicesToLoadCount = 0; 386499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 387499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCache) { 388499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (containsAndIsValid(position)) { 389499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // return the info if it exists in the window and is loaded 390499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCache[getCacheIndex(position)]; 391c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 392499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 393499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // if necessary update the window and load the new information 394499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int centerPosition = (mViewCacheEndPosition + mViewCacheStartPosition) / 2; 395499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if ((mViewCacheEndPosition <= mViewCacheStartPosition) || (Math.abs(position - centerPosition) > mCacheSlack)) { 396499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int newStartPosition = position - mHalfCacheSize; 397499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int newEndPosition = position + mHalfCacheSize; 398c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung int frameSize = mHalfCacheSize / 4; 399c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung int frameCount = (int) Math.ceil(mViewCache.length / (float) frameSize); 400499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 401499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // prune/add before the current start position 402499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int effectiveStart = Math.max(newStartPosition, 0); 403c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung int effectiveEnd = Math.min(newEndPosition, getCount() - 1); 404499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 405499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // invalidate items in the queue 406499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int overlapStart = Math.max(mViewCacheStartPosition, effectiveStart); 407499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int overlapEnd = Math.min(Math.max(mViewCacheStartPosition, mViewCacheEndPosition), effectiveEnd); 408c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung for (int i = 0; i < (frameSize * frameCount); ++i) { 409c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung int index = newStartPosition + ((i % frameSize) * frameCount + (i / frameSize)); 410c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung 411c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (index <= newEndPosition) { 412c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if ((overlapStart <= index) && (index <= overlapEnd)) { 413c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // load the stuff in the middle that has not already 414c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // been loaded 415c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (!mViewCache[getCacheIndex(index)].isValid()) { 416c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mTmpViewCacheLoadIndices[indicesToLoadCount++] = index; 417c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 418c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } else if ((effectiveStart <= index) && (index <= effectiveEnd)) { 419c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // invalidate and load all new effective items 420c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mViewCache[getCacheIndex(index)].invalidate(); 421c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mTmpViewCacheLoadIndices[indicesToLoadCount++] = index; 422c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } else { 423c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // invalidate all other cache indices (outside the effective start/end) 424c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // but don't load 425c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mViewCache[getCacheIndex(index)].invalidate(); 426499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 427499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 428499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 429499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 430499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCacheStartPosition = newStartPosition; 431499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCacheEndPosition = newEndPosition; 432499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 433499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 434499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 435499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // post items to be loaded 436499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int length = 0; 437499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCacheInfo) { 438499cb9f516062b654952d282f211bee44c31a3c2Winson Chung length = mViewCacheInfo.count; 439499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 440c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (indicesToLoadCount > 0) { 441c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung synchronized (mViewCacheLoadIndices) { 442c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mViewCacheLoadIndices.clear(); 443c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung for (int i = 0; i < indicesToLoadCount; ++i) { 444c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung final int index = mTmpViewCacheLoadIndices[i]; 445c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (0 <= index && index < length) { 446c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mViewCacheLoadIndices.addLast(index); 447499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 448c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 449499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 450499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 451499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 452499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // return null so that a dummy view can be retrieved 453499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return null; 454499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 455499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 456499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public View getView(int position, View convertView, ViewGroup parent) { 457499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (mServiceConnection.isConnected()) { 458499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // create the flipper views if necessary (we have to do this now 459499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // for all the flippers while we have the reference to the parent) 460c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung initializeLoadingViews(parent); 461499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 462499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // request the item from the cache (queueing it to load if not 463499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // in the cache already) 464499cb9f516062b654952d282f211bee44c31a3c2Winson Chung RemoteViewsIndexInfo indexInfo = requestCachedIndexInfo(position); 465499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 466499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // update the flipper appropriately 467499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCache) { 468499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int cacheIndex = getCacheIndex(position); 469499cb9f516062b654952d282f211bee44c31a3c2Winson Chung FrameLayout flipper = mViewCache[cacheIndex].flipper; 470c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung flipper.setVisibility(View.VISIBLE); 47144729e3d1c01265858eec566c7b7c676c46a7916Adam Cohen flipper.setAlpha(1.0f); 472499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 473499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (indexInfo == null) { 474499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // hide the item view and show the loading view 475499cb9f516062b654952d282f211bee44c31a3c2Winson Chung flipper.getChildAt(0).setVisibility(View.VISIBLE); 476499cb9f516062b654952d282f211bee44c31a3c2Winson Chung for (int i = 1; i < flipper.getChildCount(); ++i) { 477499cb9f516062b654952d282f211bee44c31a3c2Winson Chung flipper.getChildAt(i).setVisibility(View.GONE); 478499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 479499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } else { 480499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // hide the loading view and show the item view 481499cb9f516062b654952d282f211bee44c31a3c2Winson Chung for (int i = 0; i < flipper.getChildCount() - 1; ++i) { 482499cb9f516062b654952d282f211bee44c31a3c2Winson Chung flipper.getChildAt(i).setVisibility(View.GONE); 483499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 484499cb9f516062b654952d282f211bee44c31a3c2Winson Chung flipper.getChildAt(flipper.getChildCount() - 1).setVisibility(View.VISIBLE); 485499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 486499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return flipper; 487499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 488499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 489499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return new View(mContext); 490499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 491499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 492c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung private void initializeLoadingViews(ViewGroup parent) { 493499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // ensure that the cache has the appropriate initial flipper 494499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCache) { 495499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (mViewCache[0].flipper == null) { 496499cb9f516062b654952d282f211bee44c31a3c2Winson Chung for (int i = 0; i < mViewCache.length; ++i) { 497499cb9f516062b654952d282f211bee44c31a3c2Winson Chung FrameLayout flipper = new FrameLayout(mContext); 498499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (mUserLoadingView != null) { 499499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // use the user-specified loading view 500499cb9f516062b654952d282f211bee44c31a3c2Winson Chung flipper.addView(mUserLoadingView.apply(mContext, parent)); 501499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } else { 502499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // calculate the original size of the first row for the loader view 503499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCacheInfo) { 504499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (mFirstViewHeight < 0) { 505499cb9f516062b654952d282f211bee44c31a3c2Winson Chung View firstView = mFirstView.apply(mContext, parent); 506499cb9f516062b654952d282f211bee44c31a3c2Winson Chung firstView.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 507499cb9f516062b654952d282f211bee44c31a3c2Winson Chung MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); 508499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mFirstViewHeight = firstView.getMeasuredHeight(); 509499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 510499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 511499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 512499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // construct a new loader and add it to the flipper as the fallback 513499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // default view 514499cb9f516062b654952d282f211bee44c31a3c2Winson Chung TextView textView = new TextView(mContext); 515499cb9f516062b654952d282f211bee44c31a3c2Winson Chung textView.setText("Loading..."); 516499cb9f516062b654952d282f211bee44c31a3c2Winson Chung textView.setHeight(mFirstViewHeight); 517499cb9f516062b654952d282f211bee44c31a3c2Winson Chung textView.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL); 518499cb9f516062b654952d282f211bee44c31a3c2Winson Chung textView.setTextSize(18.0f); 519499cb9f516062b654952d282f211bee44c31a3c2Winson Chung textView.setTextColor(Color.argb(96, 255, 255, 255)); 520499cb9f516062b654952d282f211bee44c31a3c2Winson Chung textView.setShadowLayer(2.0f, 0.0f, 1.0f, Color.BLACK); 521499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 522499cb9f516062b654952d282f211bee44c31a3c2Winson Chung flipper.addView(textView); 523499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 524499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCache[i].flipper = flipper; 525499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 526499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 527499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 528499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 529499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 530c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung public void startBackgroundLoader() { 531c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // initialize the worker runnable 532c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mBackgroundLoaderEnabled = true; 533c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mWorkerQueue.post(new Runnable() { 534c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung @Override 535c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung public void run() { 536c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung while (mBackgroundLoaderEnabled) { 5376394c0e52cf641d93f678fd052499aa952e3595dWinson Chung // notify the RemoteViews factory if necessary 5386394c0e52cf641d93f678fd052499aa952e3595dWinson Chung boolean isDataDirty = false; 5396394c0e52cf641d93f678fd052499aa952e3595dWinson Chung synchronized (mViewCacheInfo) { 5406394c0e52cf641d93f678fd052499aa952e3595dWinson Chung isDataDirty = mViewCacheInfo.isDataDirty; 5416394c0e52cf641d93f678fd052499aa952e3595dWinson Chung mViewCacheInfo.isDataDirty = false; 5426394c0e52cf641d93f678fd052499aa952e3595dWinson Chung } 5436394c0e52cf641d93f678fd052499aa952e3595dWinson Chung if (isDataDirty) { 5446394c0e52cf641d93f678fd052499aa952e3595dWinson Chung updateNotifyDataSetChanged(); 5456394c0e52cf641d93f678fd052499aa952e3595dWinson Chung } 5466394c0e52cf641d93f678fd052499aa952e3595dWinson Chung 547c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung int index = -1; 548c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung synchronized (mViewCacheLoadIndices) { 549c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (!mViewCacheLoadIndices.isEmpty()) { 550c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung index = mViewCacheLoadIndices.removeFirst(); 551c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 552c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 553c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung if (index < 0) { 554c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // there were no items to load, so sleep for a bit 555c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung try { 556c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung Thread.sleep(10); 557c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } catch (InterruptedException e) { 558c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung e.printStackTrace(); 559c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 560c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } else { 561c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // otherwise, try and load the item 562c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung updateRemoteViewsInfo(index); 563c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung 564c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // sleep for a bit to allow things to catch up after the load 565c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung try { 566c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung Thread.sleep(50); 567c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } catch (InterruptedException e) { 568c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung e.printStackTrace(); 569c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 570c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 571c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 572c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 573c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung }); 574c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 575c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung 576c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung public void stopBackgroundLoader() { 577c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // clear the items to be loaded 578c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mBackgroundLoaderEnabled = false; 579c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung synchronized (mViewCacheLoadIndices) { 580c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mViewCacheLoadIndices.clear(); 581c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 582c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 583c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung 584499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public long getItemId(int position) { 585499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCache) { 586499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (containsAndIsValid(position)) { 587499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCache[getCacheIndex(position)].itemId; 588499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 589499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 590499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return 0; 591499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 592499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 593499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public int getItemViewType(int position) { 594499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // synchronize to ensure that the type id/index map is updated synchronously 595499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCache) { 596499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (containsAndIsValid(position)) { 597499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int viewId = mViewCache[getCacheIndex(position)].typeId; 598499cb9f516062b654952d282f211bee44c31a3c2Winson Chung Map<Integer, Integer> typeMap = mViewCacheInfo.mTypeIdIndexMap; 599499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // we +1 because the default dummy view get view type 0 600499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (typeMap.containsKey(viewId)) { 601499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return typeMap.get(viewId); 602499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } else { 603499cb9f516062b654952d282f211bee44c31a3c2Winson Chung int newIndex = typeMap.size() + 1; 604499cb9f516062b654952d282f211bee44c31a3c2Winson Chung typeMap.put(viewId, newIndex); 605499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return newIndex; 606499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 607499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 608499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 609499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // return the type of the default item 610499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return 0; 611499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 612499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 613499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public int getCount() { 614499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCacheInfo) { 615499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCacheInfo.count; 616499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 617499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 618499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 619499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public int getViewTypeCount() { 620499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCacheInfo) { 621499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCacheInfo.viewTypeCount; 622499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 623499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 624499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 625499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public boolean hasStableIds() { 626499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCacheInfo) { 627499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCacheInfo.hasStableIds; 628499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 629499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 630499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 631499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public void flushCache() { 632c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung // clear the items to be loaded 633c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung synchronized (mViewCacheLoadIndices) { 634c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung mViewCacheLoadIndices.clear(); 635c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung } 636c6d6d4a4e73fcb63eaa13d66fcbf26d847799838Winson Chung 637499cb9f516062b654952d282f211bee44c31a3c2Winson Chung synchronized (mViewCache) { 638499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // flush the internal cache and invalidate the adapter for future loads 639499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mMainQueue.removeMessages(0); 640499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 641499cb9f516062b654952d282f211bee44c31a3c2Winson Chung for (int i = 0; i < mViewCache.length; ++i) { 642499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCache[i].invalidate(); 643499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 644499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 645499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCacheStartPosition = 0; 646499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCacheEndPosition = -1; 647499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 648499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 649499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 650499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 651499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public RemoteViewsAdapter(Context context, Intent intent, RemoteAdapterConnectionCallback callback) { 652499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mContext = context; 653499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mIntent = intent; 654499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 655499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // initialize the worker thread 656499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mWorkerThread = new HandlerThread("RemoteViewsCache-loader"); 657499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mWorkerThread.start(); 658499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mWorkerQueue = new Handler(mWorkerThread.getLooper()); 659499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mWorkerPriorityQueue = new Handler(mWorkerThread.getLooper()); 660499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mMainQueue = new Handler(Looper.myLooper()); 661499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mMainPriorityQueue = new Handler(Looper.myLooper()); 662499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 663499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // initialize the cache and the service connection on startup 664499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCache = new RemoteViewsCache(25); 665499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mServiceConnection = new RemoteViewsAdapterServiceConnection(callback); 666499cb9f516062b654952d282f211bee44c31a3c2Winson Chung requestBindService(); 667499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 668499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 669499cb9f516062b654952d282f211bee44c31a3c2Winson Chung protected void finalize() throws Throwable { 670499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // remember to unbind from the service when finalizing 671499cb9f516062b654952d282f211bee44c31a3c2Winson Chung unbindService(); 672499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 673499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 674499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public int getCount() { 675499cb9f516062b654952d282f211bee44c31a3c2Winson Chung requestBindService(); 676499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCache.getCount(); 677499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 678499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 679499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public Object getItem(int position) { 680499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // disallow arbitrary object to be associated with an item for the time being 681499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return null; 682499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 683499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 684499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public long getItemId(int position) { 685499cb9f516062b654952d282f211bee44c31a3c2Winson Chung requestBindService(); 686499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCache.getItemId(position); 687499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 688499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 689499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public int getItemViewType(int position) { 690499cb9f516062b654952d282f211bee44c31a3c2Winson Chung requestBindService(); 691499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCache.getItemViewType(position); 692499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 693499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 694499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public View getView(int position, View convertView, ViewGroup parent) { 695499cb9f516062b654952d282f211bee44c31a3c2Winson Chung requestBindService(); 696499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCache.getView(position, convertView, parent); 697499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 698499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 699499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public int getViewTypeCount() { 700499cb9f516062b654952d282f211bee44c31a3c2Winson Chung requestBindService(); 701499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCache.getViewTypeCount(); 702499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 703499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 704499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public boolean hasStableIds() { 705499cb9f516062b654952d282f211bee44c31a3c2Winson Chung requestBindService(); 706499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mViewCache.hasStableIds(); 707499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 708499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 709499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public boolean isEmpty() { 710499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return getCount() <= 0; 711499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 712499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 713499cb9f516062b654952d282f211bee44c31a3c2Winson Chung public void notifyDataSetChanged() { 714499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // flush the cache so that we can reload new items from the service 715499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mViewCache.flushCache(); 7166394c0e52cf641d93f678fd052499aa952e3595dWinson Chung 7176394c0e52cf641d93f678fd052499aa952e3595dWinson Chung // notify the factory that it's data may no longer be valid 7186394c0e52cf641d93f678fd052499aa952e3595dWinson Chung mViewCache.onNotifyDataSetChanged(); 7196394c0e52cf641d93f678fd052499aa952e3595dWinson Chung } 7206394c0e52cf641d93f678fd052499aa952e3595dWinson Chung 7216394c0e52cf641d93f678fd052499aa952e3595dWinson Chung public void completeNotifyDataSetChanged() { 722499cb9f516062b654952d282f211bee44c31a3c2Winson Chung super.notifyDataSetChanged(); 723499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 724499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 725499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private boolean requestBindService() { 726499cb9f516062b654952d282f211bee44c31a3c2Winson Chung // try binding the service (which will start it if it's not already running) 727499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (!mServiceConnection.isConnected()) { 728499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mContext.bindService(mIntent, mServiceConnection, Context.BIND_AUTO_CREATE); 729499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 730499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 731499cb9f516062b654952d282f211bee44c31a3c2Winson Chung return mServiceConnection.isConnected(); 732499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 733499cb9f516062b654952d282f211bee44c31a3c2Winson Chung 734499cb9f516062b654952d282f211bee44c31a3c2Winson Chung private void unbindService() { 735499cb9f516062b654952d282f211bee44c31a3c2Winson Chung if (mServiceConnection.isConnected()) { 736499cb9f516062b654952d282f211bee44c31a3c2Winson Chung mContext.unbindService(mServiceConnection); 737499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 738499cb9f516062b654952d282f211bee44c31a3c2Winson Chung } 739499cb9f516062b654952d282f211bee44c31a3c2Winson Chung} 740