Merge "Caching the FixedSizeRemoteViewsCaches across rotation" into jb-dev
This commit is contained in:
@@ -16,8 +16,6 @@
|
|||||||
|
|
||||||
package android.widget;
|
package android.widget;
|
||||||
|
|
||||||
import com.android.internal.R;
|
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.res.TypedArray;
|
import android.content.res.TypedArray;
|
||||||
@@ -69,6 +67,8 @@ import android.view.inputmethod.InputConnection;
|
|||||||
import android.view.inputmethod.InputConnectionWrapper;
|
import android.view.inputmethod.InputConnectionWrapper;
|
||||||
import android.view.inputmethod.InputMethodManager;
|
import android.view.inputmethod.InputMethodManager;
|
||||||
|
|
||||||
|
import com.android.internal.R;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -1813,6 +1813,10 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
}
|
}
|
||||||
ss.checkedItemCount = mCheckedItemCount;
|
ss.checkedItemCount = mCheckedItemCount;
|
||||||
|
|
||||||
|
if (mRemoteAdapter != null) {
|
||||||
|
mRemoteAdapter.saveRemoteViewsCache();
|
||||||
|
}
|
||||||
|
|
||||||
return ss;
|
return ss;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5974,6 +5978,9 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
|
|||||||
mDeferNotifyDataSetChanged = false;
|
mDeferNotifyDataSetChanged = false;
|
||||||
// Otherwise, create a new RemoteViewsAdapter for binding
|
// Otherwise, create a new RemoteViewsAdapter for binding
|
||||||
mRemoteAdapter = new RemoteViewsAdapter(getContext(), intent, this);
|
mRemoteAdapter = new RemoteViewsAdapter(getContext(), intent, this);
|
||||||
|
if (mRemoteAdapter.isDataReady()) {
|
||||||
|
setAdapter(mRemoteAdapter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -813,6 +813,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
|
|||||||
@Override
|
@Override
|
||||||
public Parcelable onSaveInstanceState() {
|
public Parcelable onSaveInstanceState() {
|
||||||
Parcelable superState = super.onSaveInstanceState();
|
Parcelable superState = super.onSaveInstanceState();
|
||||||
|
if (mRemoteViewsAdapter != null) {
|
||||||
|
mRemoteViewsAdapter.saveRemoteViewsCache();
|
||||||
|
}
|
||||||
return new SavedState(superState, mWhichChild);
|
return new SavedState(superState, mWhichChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -984,6 +987,9 @@ public abstract class AdapterViewAnimator extends AdapterView<Adapter>
|
|||||||
mDeferNotifyDataSetChanged = false;
|
mDeferNotifyDataSetChanged = false;
|
||||||
// Otherwise, create a new RemoteViewsAdapter for binding
|
// Otherwise, create a new RemoteViewsAdapter for binding
|
||||||
mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this);
|
mRemoteViewsAdapter = new RemoteViewsAdapter(getContext(), intent, this);
|
||||||
|
if (mRemoteViewsAdapter.isDataReady()) {
|
||||||
|
setAdapter(mRemoteViewsAdapter);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -29,12 +29,16 @@ import android.os.HandlerThread;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
import android.os.Message;
|
import android.os.Message;
|
||||||
|
import android.os.Parcel;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
import android.util.Pair;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.MeasureSpec;
|
import android.view.View.MeasureSpec;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.RemoteViewsService.RemoteViewsFactory;
|
||||||
|
|
||||||
import com.android.internal.widget.IRemoteViewsAdapterConnection;
|
import com.android.internal.widget.IRemoteViewsAdapterConnection;
|
||||||
import com.android.internal.widget.IRemoteViewsFactory;
|
import com.android.internal.widget.IRemoteViewsFactory;
|
||||||
@@ -83,6 +87,26 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
private Handler mWorkerQueue;
|
private Handler mWorkerQueue;
|
||||||
private Handler mMainQueue;
|
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
|
* An interface for the RemoteAdapter to notify other classes when adapters
|
||||||
* are actually connected to/disconnected from their actual services.
|
* are actually connected to/disconnected from their actual services.
|
||||||
@@ -331,7 +355,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
/**
|
/**
|
||||||
* The meta-data associated with the cache in it's current state.
|
* 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 count;
|
||||||
int viewTypeCount;
|
int viewTypeCount;
|
||||||
boolean hasStableIds;
|
boolean hasStableIds;
|
||||||
@@ -350,6 +374,51 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
reset();
|
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) {
|
public void set(RemoteViewsMetaData d) {
|
||||||
synchronized (d) {
|
synchronized (d) {
|
||||||
count = d.count;
|
count = d.count;
|
||||||
@@ -460,7 +529,7 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
/**
|
/**
|
||||||
* The meta-data associated with a single item in the cache.
|
* The meta-data associated with a single item in the cache.
|
||||||
*/
|
*/
|
||||||
private static class RemoteViewsIndexMetaData {
|
private static class RemoteViewsIndexMetaData implements Parcelable {
|
||||||
int typeId;
|
int typeId;
|
||||||
long itemId;
|
long itemId;
|
||||||
boolean isRequested;
|
boolean isRequested;
|
||||||
@@ -469,6 +538,22 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
set(v, itemId, requested);
|
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) {
|
public void set(RemoteViews v, long id, boolean requested) {
|
||||||
itemId = id;
|
itemId = id;
|
||||||
if (v != null) {
|
if (v != null) {
|
||||||
@@ -478,12 +563,14 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
}
|
}
|
||||||
isRequested = requested;
|
isRequested = requested;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static class FixedSizeRemoteViewsCache {
|
private static class FixedSizeRemoteViewsCache implements Parcelable {
|
||||||
private static final String TAG = "FixedSizeRemoteViewsCache";
|
private static final String TAG = "FixedSizeRemoteViewsCache";
|
||||||
|
|
||||||
// The meta data related to all the RemoteViews, ie. count, is stable, etc.
|
// The meta data related to all the RemoteViews, ie. count, is stable, etc.
|
||||||
@@ -545,6 +632,57 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
mLoadIndices = new HashSet<Integer>();
|
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) {
|
public void insert(int position, RemoteViews v, long itemId, boolean isRequested) {
|
||||||
// Trim the cache if we go beyond the count
|
// Trim the cache if we go beyond the count
|
||||||
if (mIndexRemoteViews.size() >= mMaxCount) {
|
if (mIndexRemoteViews.size() >= mMaxCount) {
|
||||||
@@ -747,11 +885,30 @@ public class RemoteViewsAdapter extends BaseAdapter implements Handler.Callback
|
|||||||
mWorkerQueue = new Handler(mWorkerThread.getLooper());
|
mWorkerQueue = new Handler(mWorkerThread.getLooper());
|
||||||
mMainQueue = new Handler(Looper.myLooper(), this);
|
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
|
// Initialize the cache and the service connection on startup
|
||||||
mCache = new FixedSizeRemoteViewsCache(sDefaultCacheSize);
|
|
||||||
mCallback = new WeakReference<RemoteAdapterConnectionCallback>(callback);
|
mCallback = new WeakReference<RemoteAdapterConnectionCallback>(callback);
|
||||||
mServiceConnection = new RemoteViewsAdapterServiceConnection(this);
|
mServiceConnection = new RemoteViewsAdapterServiceConnection(this);
|
||||||
requestBindService();
|
|
||||||
|
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
|
@Override
|
||||||
@@ -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() {
|
private void loadNextIndexInBackground() {
|
||||||
mWorkerQueue.post(new Runnable() {
|
mWorkerQueue.post(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
Reference in New Issue
Block a user