Loading core/java/android/widget/AbsListView.java +9 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package android.widget; import com.android.internal.R; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; Loading Loading @@ -69,6 +67,8 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionWrapper; import android.view.inputmethod.InputMethodManager; import com.android.internal.R; import java.util.ArrayList; import java.util.List; Loading Loading @@ -1813,6 +1813,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } ss.checkedItemCount = mCheckedItemCount; if (mRemoteAdapter != null) { mRemoteAdapter.saveRemoteViewsCache(); } return ss; } Loading Loading @@ -5974,6 +5978,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mDeferNotifyDataSetChanged = false; // Otherwise, create a new RemoteViewsAdapter for binding mRemoteAdapter = new RemoteViewsAdapter(getContext(), intent, this); if (mRemoteAdapter.isDataReady()) { setAdapter(mRemoteAdapter); } } /** Loading core/java/android/widget/AdapterViewAnimator.java +6 −0 Original line number Diff line number Diff line Loading @@ -813,6 +813,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); if (mRemoteViewsAdapter != null) { mRemoteViewsAdapter.saveRemoteViewsCache(); } return new SavedState(superState, mWhichChild); } Loading Loading @@ -984,6 +987,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> mDeferNotifyDataSetChanged = false; // Otherwise, create a new RemoteViewsAdapter for binding mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this); if (mRemoteViewsAdapter.isDataReady()) { setAdapter(mRemoteViewsAdapter); } } @Override Loading core/java/android/widget/RemoteViewsAdapter.java +200 −5 Original line number Diff line number Diff line Loading @@ -29,12 +29,16 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.widget.RemoteViewsService.RemoteViewsFactory; import com.android.internal.widget.IRemoteViewsAdapterConnection; import com.android.internal.widget.IRemoteViewsFactory; Loading Loading @@ -83,6 +87,26 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback private Handler mWorkerQueue; private Handler mMainQueue; // We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data // structures; private static final HashMap<Pair<Intent.FilterComparison, Integer>, Parcel> sCachedRemoteViewsCaches = new HashMap<Pair<Intent.FilterComparison, Integer>, Parcel>(); private static final HashMap<Pair<Intent.FilterComparison, Integer>, Runnable> sRemoteViewsCacheRemoveRunnables = new HashMap<Pair<Intent.FilterComparison, Integer>, Runnable>(); private static HandlerThread sCacheRemovalThread; private static Handler sCacheRemovalQueue; // We keep the cache around for a duration after onSaveInstanceState for use on re-inflation. // If a new RemoteViewsAdapter with the same intent / widget id isn't constructed within this // duration, the cache is dropped. private static final int REMOTE_VIEWS_CACHE_DURATION = 5000; // Used to indicate to the AdapterView that it can use this Adapter immediately after // construction (happens when we have a cached FixedSizeRemoteViewsCache). private boolean mDataReady = false; /** * An interface for the RemoteAdapter to notify other classes when adapters * are actually connected to/disconnected from their actual services. Loading Loading @@ -331,7 +355,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback /** * The meta-data associated with the cache in it's current state. */ private static class RemoteViewsMetaData { private static class RemoteViewsMetaData implements Parcelable { int count; int viewTypeCount; boolean hasStableIds; Loading @@ -350,6 +374,51 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback reset(); } public RemoteViewsMetaData(Parcel src) { count = src.readInt(); viewTypeCount = src.readInt(); hasStableIds = src.readInt() == 0 ? false : true; mFirstViewHeight = src.readInt(); if (src.readInt() != 0) { mUserLoadingView = new RemoteViews(src); } if (src.readInt() != 0) { mFirstView = new RemoteViews(src); } int count = src.readInt(); for (int i = 0; i < count; i++) { mTypeIdIndexMap.put(src.readInt(), src.readInt()); } } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(count); dest.writeInt(viewTypeCount); dest.writeInt(hasStableIds ? 1 : 0); dest.writeInt(mFirstViewHeight); dest.writeInt(mUserLoadingView != null ? 1 : 0); if (mUserLoadingView != null) { mUserLoadingView.writeToParcel(dest, flags); } dest.writeInt(mFirstView != null ? 1 : 0); if (mFirstView != null) { mFirstView.writeToParcel(dest, flags); } int count = mTypeIdIndexMap.size(); dest.writeInt(count); for (Integer key: mTypeIdIndexMap.keySet()) { dest.writeInt(key); dest.writeInt(mTypeIdIndexMap.get(key)); } } @Override public int describeContents() { return 0; } public void set(RemoteViewsMetaData d) { synchronized (d) { count = d.count; Loading Loading @@ -460,7 +529,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback /** * The meta-data associated with a single item in the cache. */ private static class RemoteViewsIndexMetaData { private static class RemoteViewsIndexMetaData implements Parcelable { int typeId; long itemId; boolean isRequested; Loading @@ -469,6 +538,22 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback set(v, itemId, requested); } public RemoteViewsIndexMetaData(Parcel src) { typeId = src.readInt(); itemId = src.readLong(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(typeId); dest.writeLong(itemId); } @Override public int describeContents() { return 0; } public void set(RemoteViews v, long id, boolean requested) { itemId = id; if (v != null) { Loading @@ -478,12 +563,14 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } isRequested = requested; } } /** * */ private static class FixedSizeRemoteViewsCache { private static class FixedSizeRemoteViewsCache implements Parcelable { private static final String TAG = "FixedSizeRemoteViewsCache"; // The meta data related to all the RemoteViews, ie. count, is stable, etc. Loading Loading @@ -545,6 +632,57 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback mLoadIndices = new HashSet<Integer>(); } public FixedSizeRemoteViewsCache(Parcel src) { mMaxCount = src.readInt(); mMaxCountSlack = src.readInt(); mPreloadLowerBound = src.readInt(); mPreloadUpperBound = src.readInt(); mMetaData = new RemoteViewsMetaData(src); int count = src.readInt(); mIndexMetaData = new HashMap<Integer, RemoteViewsIndexMetaData>(); for (int i = 0; i < count; i++) { mIndexMetaData.put(src.readInt(), new RemoteViewsIndexMetaData(src)); } count = src.readInt(); mIndexRemoteViews = new HashMap<Integer, RemoteViews>(); for (int i = 0; i < count; i++) { mIndexRemoteViews.put(src.readInt(), new RemoteViews(src)); } mTemporaryMetaData = new RemoteViewsMetaData(); mRequestedIndices = new HashSet<Integer>(); mLastRequestedIndex = -1; mLoadIndices = new HashSet<Integer>(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mMaxCount); dest.writeInt(mMaxCountSlack); dest.writeInt(mPreloadLowerBound); dest.writeInt(mPreloadUpperBound); mMetaData.writeToParcel(dest, 0); // We write the index data and cache int count = mIndexMetaData.size(); dest.writeInt(count); for (Integer key: mIndexMetaData.keySet()) { dest.writeInt(key); mIndexMetaData.get(key).writeToParcel(dest, flags); } count = mIndexRemoteViews.size(); dest.writeInt(count); for (Integer key: mIndexRemoteViews.keySet()) { dest.writeInt(key); mIndexRemoteViews.get(key).writeToParcel(dest, flags); } } @Override public int describeContents() { return 0; } public void insert(int position, RemoteViews v, long itemId, boolean isRequested) { // Trim the cache if we go beyond the count if (mIndexRemoteViews.size() >= mMaxCount) { Loading Loading @@ -747,12 +885,31 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback mWorkerQueue = new Handler(mWorkerThread.getLooper()); mMainQueue = new Handler(Looper.myLooper(), this); if (sCacheRemovalThread == null) { sCacheRemovalThread = new HandlerThread("RemoteViewsAdapter-cachePruner"); sCacheRemovalThread.start(); sCacheRemovalQueue = new Handler(sCacheRemovalThread.getLooper()); } // Initialize the cache and the service connection on startup mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize); mCallback = new WeakReference<RemoteAdapterConnectionCallback>(callback); mServiceConnection = new RemoteViewsAdapterServiceConnection(this); Pair<Intent.FilterComparison, Integer> key = new Pair<Intent.FilterComparison, Integer> (new Intent.FilterComparison(mIntent), mAppWidgetId); synchronized(sCachedRemoteViewsCaches) { if (sCachedRemoteViewsCaches.containsKey(key)) { Parcel src = sCachedRemoteViewsCaches.get(key); src.setDataPosition(0); mCache = new FixedSizeRemoteViewsCache(src); mDataReady = true; } else { mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize); requestBindService(); } } } @Override protected void finalize() throws Throwable { Loading @@ -765,6 +922,44 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } } public boolean isDataReady() { return mDataReady; } public void saveRemoteViewsCache() { final Pair<Intent.FilterComparison, Integer> key = new Pair<Intent.FilterComparison, Integer> (new Intent.FilterComparison(mIntent), mAppWidgetId); synchronized(sCachedRemoteViewsCaches) { // If we already have a remove runnable posted for this key, remove it. if (sRemoteViewsCacheRemoveRunnables.containsKey(key)) { sCacheRemovalQueue.removeCallbacks(sRemoteViewsCacheRemoveRunnables.get(key)); sRemoteViewsCacheRemoveRunnables.remove(key); } Parcel p = Parcel.obtain(); synchronized(mCache) { mCache.writeToParcel(p, 0); } sCachedRemoteViewsCaches.put(key, p); Runnable r = new Runnable() { @Override public void run() { synchronized (sCachedRemoteViewsCaches) { if (sCachedRemoteViewsCaches.containsKey(key)) { sCachedRemoteViewsCaches.remove(key); } if (sRemoteViewsCacheRemoveRunnables.containsKey(key)) { sRemoteViewsCacheRemoveRunnables.remove(key); } } } }; sRemoteViewsCacheRemoveRunnables.put(key, r); sCacheRemovalQueue.postDelayed(r, REMOTE_VIEWS_CACHE_DURATION); } } private void loadNextIndexInBackground() { mWorkerQueue.post(new Runnable() { @Override Loading Loading
core/java/android/widget/AbsListView.java +9 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package android.widget; import com.android.internal.R; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; Loading Loading @@ -69,6 +67,8 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputConnectionWrapper; import android.view.inputmethod.InputMethodManager; import com.android.internal.R; import java.util.ArrayList; import java.util.List; Loading Loading @@ -1813,6 +1813,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te } ss.checkedItemCount = mCheckedItemCount; if (mRemoteAdapter != null) { mRemoteAdapter.saveRemoteViewsCache(); } return ss; } Loading Loading @@ -5974,6 +5978,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te mDeferNotifyDataSetChanged = false; // Otherwise, create a new RemoteViewsAdapter for binding mRemoteAdapter = new RemoteViewsAdapter(getContext(), intent, this); if (mRemoteAdapter.isDataReady()) { setAdapter(mRemoteAdapter); } } /** Loading
core/java/android/widget/AdapterViewAnimator.java +6 −0 Original line number Diff line number Diff line Loading @@ -813,6 +813,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> @Override public Parcelable onSaveInstanceState() { Parcelable superState = super.onSaveInstanceState(); if (mRemoteViewsAdapter != null) { mRemoteViewsAdapter.saveRemoteViewsCache(); } return new SavedState(superState, mWhichChild); } Loading Loading @@ -984,6 +987,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter> mDeferNotifyDataSetChanged = false; // Otherwise, create a new RemoteViewsAdapter for binding mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this); if (mRemoteViewsAdapter.isDataReady()) { setAdapter(mRemoteViewsAdapter); } } @Override Loading
core/java/android/widget/RemoteViewsAdapter.java +200 −5 Original line number Diff line number Diff line Loading @@ -29,12 +29,16 @@ import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Parcel; import android.os.Parcelable; import android.os.RemoteException; import android.util.Log; import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.widget.RemoteViewsService.RemoteViewsFactory; import com.android.internal.widget.IRemoteViewsAdapterConnection; import com.android.internal.widget.IRemoteViewsFactory; Loading Loading @@ -83,6 +87,26 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback private Handler mWorkerQueue; private Handler mMainQueue; // We cache the FixedSizeRemoteViewsCaches across orientation. These are the related data // structures; private static final HashMap<Pair<Intent.FilterComparison, Integer>, Parcel> sCachedRemoteViewsCaches = new HashMap<Pair<Intent.FilterComparison, Integer>, Parcel>(); private static final HashMap<Pair<Intent.FilterComparison, Integer>, Runnable> sRemoteViewsCacheRemoveRunnables = new HashMap<Pair<Intent.FilterComparison, Integer>, Runnable>(); private static HandlerThread sCacheRemovalThread; private static Handler sCacheRemovalQueue; // We keep the cache around for a duration after onSaveInstanceState for use on re-inflation. // If a new RemoteViewsAdapter with the same intent / widget id isn't constructed within this // duration, the cache is dropped. private static final int REMOTE_VIEWS_CACHE_DURATION = 5000; // Used to indicate to the AdapterView that it can use this Adapter immediately after // construction (happens when we have a cached FixedSizeRemoteViewsCache). private boolean mDataReady = false; /** * An interface for the RemoteAdapter to notify other classes when adapters * are actually connected to/disconnected from their actual services. Loading Loading @@ -331,7 +355,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback /** * The meta-data associated with the cache in it's current state. */ private static class RemoteViewsMetaData { private static class RemoteViewsMetaData implements Parcelable { int count; int viewTypeCount; boolean hasStableIds; Loading @@ -350,6 +374,51 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback reset(); } public RemoteViewsMetaData(Parcel src) { count = src.readInt(); viewTypeCount = src.readInt(); hasStableIds = src.readInt() == 0 ? false : true; mFirstViewHeight = src.readInt(); if (src.readInt() != 0) { mUserLoadingView = new RemoteViews(src); } if (src.readInt() != 0) { mFirstView = new RemoteViews(src); } int count = src.readInt(); for (int i = 0; i < count; i++) { mTypeIdIndexMap.put(src.readInt(), src.readInt()); } } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(count); dest.writeInt(viewTypeCount); dest.writeInt(hasStableIds ? 1 : 0); dest.writeInt(mFirstViewHeight); dest.writeInt(mUserLoadingView != null ? 1 : 0); if (mUserLoadingView != null) { mUserLoadingView.writeToParcel(dest, flags); } dest.writeInt(mFirstView != null ? 1 : 0); if (mFirstView != null) { mFirstView.writeToParcel(dest, flags); } int count = mTypeIdIndexMap.size(); dest.writeInt(count); for (Integer key: mTypeIdIndexMap.keySet()) { dest.writeInt(key); dest.writeInt(mTypeIdIndexMap.get(key)); } } @Override public int describeContents() { return 0; } public void set(RemoteViewsMetaData d) { synchronized (d) { count = d.count; Loading Loading @@ -460,7 +529,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback /** * The meta-data associated with a single item in the cache. */ private static class RemoteViewsIndexMetaData { private static class RemoteViewsIndexMetaData implements Parcelable { int typeId; long itemId; boolean isRequested; Loading @@ -469,6 +538,22 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback set(v, itemId, requested); } public RemoteViewsIndexMetaData(Parcel src) { typeId = src.readInt(); itemId = src.readLong(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(typeId); dest.writeLong(itemId); } @Override public int describeContents() { return 0; } public void set(RemoteViews v, long id, boolean requested) { itemId = id; if (v != null) { Loading @@ -478,12 +563,14 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } isRequested = requested; } } /** * */ private static class FixedSizeRemoteViewsCache { private static class FixedSizeRemoteViewsCache implements Parcelable { private static final String TAG = "FixedSizeRemoteViewsCache"; // The meta data related to all the RemoteViews, ie. count, is stable, etc. Loading Loading @@ -545,6 +632,57 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback mLoadIndices = new HashSet<Integer>(); } public FixedSizeRemoteViewsCache(Parcel src) { mMaxCount = src.readInt(); mMaxCountSlack = src.readInt(); mPreloadLowerBound = src.readInt(); mPreloadUpperBound = src.readInt(); mMetaData = new RemoteViewsMetaData(src); int count = src.readInt(); mIndexMetaData = new HashMap<Integer, RemoteViewsIndexMetaData>(); for (int i = 0; i < count; i++) { mIndexMetaData.put(src.readInt(), new RemoteViewsIndexMetaData(src)); } count = src.readInt(); mIndexRemoteViews = new HashMap<Integer, RemoteViews>(); for (int i = 0; i < count; i++) { mIndexRemoteViews.put(src.readInt(), new RemoteViews(src)); } mTemporaryMetaData = new RemoteViewsMetaData(); mRequestedIndices = new HashSet<Integer>(); mLastRequestedIndex = -1; mLoadIndices = new HashSet<Integer>(); } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeInt(mMaxCount); dest.writeInt(mMaxCountSlack); dest.writeInt(mPreloadLowerBound); dest.writeInt(mPreloadUpperBound); mMetaData.writeToParcel(dest, 0); // We write the index data and cache int count = mIndexMetaData.size(); dest.writeInt(count); for (Integer key: mIndexMetaData.keySet()) { dest.writeInt(key); mIndexMetaData.get(key).writeToParcel(dest, flags); } count = mIndexRemoteViews.size(); dest.writeInt(count); for (Integer key: mIndexRemoteViews.keySet()) { dest.writeInt(key); mIndexRemoteViews.get(key).writeToParcel(dest, flags); } } @Override public int describeContents() { return 0; } public void insert(int position, RemoteViews v, long itemId, boolean isRequested) { // Trim the cache if we go beyond the count if (mIndexRemoteViews.size() >= mMaxCount) { Loading Loading @@ -747,12 +885,31 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback mWorkerQueue = new Handler(mWorkerThread.getLooper()); mMainQueue = new Handler(Looper.myLooper(), this); if (sCacheRemovalThread == null) { sCacheRemovalThread = new HandlerThread("RemoteViewsAdapter-cachePruner"); sCacheRemovalThread.start(); sCacheRemovalQueue = new Handler(sCacheRemovalThread.getLooper()); } // Initialize the cache and the service connection on startup mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize); mCallback = new WeakReference<RemoteAdapterConnectionCallback>(callback); mServiceConnection = new RemoteViewsAdapterServiceConnection(this); Pair<Intent.FilterComparison, Integer> key = new Pair<Intent.FilterComparison, Integer> (new Intent.FilterComparison(mIntent), mAppWidgetId); synchronized(sCachedRemoteViewsCaches) { if (sCachedRemoteViewsCaches.containsKey(key)) { Parcel src = sCachedRemoteViewsCaches.get(key); src.setDataPosition(0); mCache = new FixedSizeRemoteViewsCache(src); mDataReady = true; } else { mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize); requestBindService(); } } } @Override protected void finalize() throws Throwable { Loading @@ -765,6 +922,44 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback } } public boolean isDataReady() { return mDataReady; } public void saveRemoteViewsCache() { final Pair<Intent.FilterComparison, Integer> key = new Pair<Intent.FilterComparison, Integer> (new Intent.FilterComparison(mIntent), mAppWidgetId); synchronized(sCachedRemoteViewsCaches) { // If we already have a remove runnable posted for this key, remove it. if (sRemoteViewsCacheRemoveRunnables.containsKey(key)) { sCacheRemovalQueue.removeCallbacks(sRemoteViewsCacheRemoveRunnables.get(key)); sRemoteViewsCacheRemoveRunnables.remove(key); } Parcel p = Parcel.obtain(); synchronized(mCache) { mCache.writeToParcel(p, 0); } sCachedRemoteViewsCaches.put(key, p); Runnable r = new Runnable() { @Override public void run() { synchronized (sCachedRemoteViewsCaches) { if (sCachedRemoteViewsCaches.containsKey(key)) { sCachedRemoteViewsCaches.remove(key); } if (sRemoteViewsCacheRemoveRunnables.containsKey(key)) { sRemoteViewsCacheRemoveRunnables.remove(key); } } } }; sRemoteViewsCacheRemoveRunnables.put(key, r); sCacheRemovalQueue.postDelayed(r, REMOTE_VIEWS_CACHE_DURATION); } } private void loadNextIndexInBackground() { mWorkerQueue.post(new Runnable() { @Override Loading