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