Merge "Merge "Update UnlockMethodCache when keyguard visibility changes" into oc-mr1-dev am: cbda08c5ec am: 9223437066"
diff --git a/api/current.txt b/api/current.txt
index c7816eb..9c39295 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -51075,10 +51075,11 @@
   public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable {
     ctor public RemoteViews(java.lang.String, int);
     ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews);
+    ctor public RemoteViews(android.widget.RemoteViews);
     ctor public RemoteViews(android.os.Parcel);
     method public void addView(int, android.widget.RemoteViews);
     method public android.view.View apply(android.content.Context, android.view.ViewGroup);
-    method public android.widget.RemoteViews clone();
+    method public deprecated android.widget.RemoteViews clone();
     method public int describeContents();
     method public int getLayoutId();
     method public java.lang.String getPackage();
diff --git a/api/system-current.txt b/api/system-current.txt
index 7e25988..4a76bfb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -55053,10 +55053,11 @@
   public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable {
     ctor public RemoteViews(java.lang.String, int);
     ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews);
+    ctor public RemoteViews(android.widget.RemoteViews);
     ctor public RemoteViews(android.os.Parcel);
     method public void addView(int, android.widget.RemoteViews);
     method public android.view.View apply(android.content.Context, android.view.ViewGroup);
-    method public android.widget.RemoteViews clone();
+    method public deprecated android.widget.RemoteViews clone();
     method public int describeContents();
     method public int getLayoutId();
     method public java.lang.String getPackage();
diff --git a/api/test-current.txt b/api/test-current.txt
index edce863..9f52666 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -51578,10 +51578,11 @@
   public class RemoteViews implements android.view.LayoutInflater.Filter android.os.Parcelable {
     ctor public RemoteViews(java.lang.String, int);
     ctor public RemoteViews(android.widget.RemoteViews, android.widget.RemoteViews);
+    ctor public RemoteViews(android.widget.RemoteViews);
     ctor public RemoteViews(android.os.Parcel);
     method public void addView(int, android.widget.RemoteViews);
     method public android.view.View apply(android.content.Context, android.view.ViewGroup);
-    method public android.widget.RemoteViews clone();
+    method public deprecated android.widget.RemoteViews clone();
     method public int describeContents();
     method public int getLayoutId();
     method public java.lang.String getPackage();
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 46742b8..bc85fad 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -144,11 +144,6 @@
     private ArrayList<Action> mActions;
 
     /**
-     * A class to keep track of memory usage by this RemoteViews
-     */
-    private MemoryUsageCounter mMemoryUsageCounter;
-
-    /**
      * Maps bitmaps to unique indicies to avoid Bitmap duplication.
      */
     private BitmapCache mBitmapCache;
@@ -294,7 +289,6 @@
         public String asyncMethodName;
     }
 
-
     /**
      * This annotation indicates that a subclass of View is allowed to be used
      * with the {@link RemoteViews} mechanism.
@@ -386,14 +380,6 @@
             return 0;
         }
 
-        /**
-         * Overridden by each class to report on it's own memory usage
-         */
-        public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
-            // We currently only calculate Bitmap memory usage, so by default,
-            // don't do anything here
-        }
-
         public void setBitmapCache(BitmapCache bitmapCache) {
             // Do nothing
         }
@@ -466,7 +452,7 @@
         // We first copy the new RemoteViews, as the process of merging modifies the way the actions
         // reference the bitmap cache. We don't want to modify the object as it may need to
         // be merged and applied multiple times.
-        RemoteViews copy = newRv.clone();
+        RemoteViews copy = new RemoteViews(newRv);
 
         HashMap<String, Action> map = new HashMap<String, Action>();
         if (mActions == null) {
@@ -500,7 +486,6 @@
         // Because pruning can remove the need for bitmaps, we reconstruct the bitmap cache
         mBitmapCache = new BitmapCache();
         setBitmapCache(mBitmapCache);
-        recalculateMemoryUsage();
     }
 
     private static class RemoteViewsContextWrapper extends ContextWrapper {
@@ -1162,15 +1147,17 @@
     }
 
     private static class BitmapCache {
+
         ArrayList<Bitmap> mBitmaps;
+        int mBitmapMemory = -1;
 
         public BitmapCache() {
-            mBitmaps = new ArrayList<Bitmap>();
+            mBitmaps = new ArrayList<>();
         }
 
         public BitmapCache(Parcel source) {
             int count = source.readInt();
-            mBitmaps = new ArrayList<Bitmap>();
+            mBitmaps = new ArrayList<>(count);
             for (int i = 0; i < count; i++) {
                 Bitmap b = Bitmap.CREATOR.createFromParcel(source);
                 mBitmaps.add(b);
@@ -1185,6 +1172,7 @@
                     return mBitmaps.indexOf(b);
                 } else {
                     mBitmaps.add(b);
+                    mBitmapMemory = -1;
                     return (mBitmaps.size() - 1);
                 }
             }
@@ -1206,28 +1194,15 @@
             }
         }
 
-        public void assimilate(BitmapCache bitmapCache) {
-            ArrayList<Bitmap> bitmapsToBeAdded = bitmapCache.mBitmaps;
-            int count = bitmapsToBeAdded.size();
-            for (int i = 0; i < count; i++) {
-                Bitmap b = bitmapsToBeAdded.get(i);
-                if (!mBitmaps.contains(b)) {
-                    mBitmaps.add(b);
+        public int getBitmapMemory() {
+            if (mBitmapMemory < 0) {
+                mBitmapMemory = 0;
+                int count = mBitmaps.size();
+                for (int i = 0; i < count; i++) {
+                    mBitmapMemory += mBitmaps.get(i).getAllocationByteCount();
                 }
             }
-        }
-
-        public void addBitmapMemory(MemoryUsageCounter memoryCounter) {
-            for (int i = 0; i < mBitmaps.size(); i++) {
-                memoryCounter.addBitmapMemory(mBitmaps.get(i));
-            }
-        }
-
-        @Override
-        protected BitmapCache clone() {
-            BitmapCache bitmapCache = new BitmapCache();
-            bitmapCache.mBitmaps.addAll(mBitmaps);
-            return bitmapCache;
+            return mBitmapMemory;
         }
     }
 
@@ -1429,37 +1404,17 @@
                 case CHAR_SEQUENCE:
                     TextUtils.writeToParcel((CharSequence)this.value, out, flags);
                     break;
-                case URI:
-                    out.writeInt(this.value != null ? 1 : 0);
-                    if (this.value != null) {
-                        ((Uri)this.value).writeToParcel(out, flags);
-                    }
-                    break;
-                case BITMAP:
-                    out.writeInt(this.value != null ? 1 : 0);
-                    if (this.value != null) {
-                        ((Bitmap)this.value).writeToParcel(out, flags);
-                    }
-                    break;
                 case BUNDLE:
                     out.writeBundle((Bundle) this.value);
                     break;
+                case URI:
+                case BITMAP:
                 case INTENT:
-                    out.writeInt(this.value != null ? 1 : 0);
-                    if (this.value != null) {
-                        ((Intent)this.value).writeToParcel(out, flags);
-                    }
-                    break;
                 case COLOR_STATE_LIST:
-                    out.writeInt(this.value != null ? 1 : 0);
-                    if (this.value != null) {
-                        ((ColorStateList)this.value).writeToParcel(out, flags);
-                    }
-                    break;
                 case ICON:
                     out.writeInt(this.value != null ? 1 : 0);
                     if (this.value != null) {
-                        ((Icon)this.value).writeToParcel(out, flags);
+                        ((Parcelable) this.value).writeToParcel(out, flags);
                     }
                     break;
                 default:
@@ -1595,7 +1550,6 @@
     }
 
     private void configureRemoteViewsAsChild(RemoteViews rv) {
-        mBitmapCache.assimilate(rv.mBitmapCache);
         rv.setBitmapCache(mBitmapCache);
         rv.setNotRoot();
     }
@@ -1693,11 +1647,6 @@
         }
 
         @Override
-        public void updateMemoryUsageEstimate(MemoryUsageCounter counter) {
-            counter.increment(mNestedViews.estimateMemoryUsage());
-        }
-
-        @Override
         public void setBitmapCache(BitmapCache bitmapCache) {
             mNestedViews.setBitmapCache(bitmapCache);
         }
@@ -2302,30 +2251,6 @@
     }
 
     /**
-     * Simple class used to keep track of memory usage in a RemoteViews.
-     *
-     */
-    private class MemoryUsageCounter {
-        public void clear() {
-            mMemoryUsage = 0;
-        }
-
-        public void increment(int numBytes) {
-            mMemoryUsage += numBytes;
-        }
-
-        public int getMemoryUsage() {
-            return mMemoryUsage;
-        }
-
-        public void addBitmapMemory(Bitmap b) {
-            increment(b.getAllocationByteCount());
-        }
-
-        int mMemoryUsage;
-    }
-
-    /**
      * Create a new RemoteViews object that will display the views contained
      * in the specified layout file.
      *
@@ -2363,9 +2288,6 @@
         mApplication = application;
         mLayoutId = layoutId;
         mBitmapCache = new BitmapCache();
-        // setup the memory usage statistics
-        mMemoryUsageCounter = new MemoryUsageCounter();
-        recalculateMemoryUsage();
     }
 
     private boolean hasLandscapeAndPortraitLayouts() {
@@ -2393,14 +2315,49 @@
         mLandscape = landscape;
         mPortrait = portrait;
 
-        // setup the memory usage statistics
-        mMemoryUsageCounter = new MemoryUsageCounter();
-
         mBitmapCache = new BitmapCache();
         configureRemoteViewsAsChild(landscape);
         configureRemoteViewsAsChild(portrait);
+    }
 
-        recalculateMemoryUsage();
+    /**
+     * Creates a copy of another RemoteViews.
+     */
+    public RemoteViews(RemoteViews src) {
+        mBitmapCache = src.mBitmapCache;
+        mApplication = src.mApplication;
+        mIsRoot = src.mIsRoot;
+        mLayoutId = src.mLayoutId;
+        mIsWidgetCollectionChild = src.mIsWidgetCollectionChild;
+        mReapplyDisallowed = src.mReapplyDisallowed;
+
+        if (src.hasLandscapeAndPortraitLayouts()) {
+            mLandscape = new RemoteViews(src.mLandscape);
+            mPortrait = new RemoteViews(src.mPortrait);
+
+        }
+
+        if (src.mActions != null) {
+            mActions = new ArrayList<>();
+
+            Parcel p = Parcel.obtain();
+            int count = src.mActions.size();
+            for (int i = 0; i < count; i++) {
+                p.setDataPosition(0);
+                Action a = src.mActions.get(i);
+                a.writeToParcel(
+                        p, a.hasSameAppInfo(mApplication) ? PARCELABLE_ELIDE_DUPLICATES : 0);
+                p.setDataPosition(0);
+                // Since src is already in memory, we do not care about stack overflow as it has
+                // already been read once.
+                mActions.add(getActionFromParcel(p, 0));
+            }
+            p.recycle();
+        }
+
+        // Now that everything is initialized and duplicated, setting a new BitmapCache will
+        // re-initialize the cache.
+        setBitmapCache(new BitmapCache());
     }
 
     /**
@@ -2437,71 +2394,9 @@
 
             int count = parcel.readInt();
             if (count > 0) {
-                mActions = new ArrayList<Action>(count);
-                for (int i=0; i<count; i++) {
-                    int tag = parcel.readInt();
-                    switch (tag) {
-                        case SET_ON_CLICK_PENDING_INTENT_TAG:
-                            mActions.add(new SetOnClickPendingIntent(parcel));
-                            break;
-                        case SET_DRAWABLE_PARAMETERS_TAG:
-                            mActions.add(new SetDrawableParameters(parcel));
-                            break;
-                        case REFLECTION_ACTION_TAG:
-                            mActions.add(new ReflectionAction(parcel));
-                            break;
-                        case VIEW_GROUP_ACTION_ADD_TAG:
-                            mActions.add(new ViewGroupActionAdd(parcel, mBitmapCache, mApplication,
-                                    depth));
-                            break;
-                        case VIEW_GROUP_ACTION_REMOVE_TAG:
-                            mActions.add(new ViewGroupActionRemove(parcel));
-                            break;
-                        case SET_REFLECTION_ACTION_WITHOUT_PARAMS_TAG:
-                            mActions.add(new ReflectionActionWithoutParams(parcel));
-                            break;
-                        case SET_EMPTY_VIEW_ACTION_TAG:
-                            mActions.add(new SetEmptyView(parcel));
-                            break;
-                        case SET_PENDING_INTENT_TEMPLATE_TAG:
-                            mActions.add(new SetPendingIntentTemplate(parcel));
-                            break;
-                        case SET_ON_CLICK_FILL_IN_INTENT_TAG:
-                            mActions.add(new SetOnClickFillInIntent(parcel));
-                            break;
-                        case SET_REMOTE_VIEW_ADAPTER_INTENT_TAG:
-                            mActions.add(new SetRemoteViewsAdapterIntent(parcel));
-                            break;
-                        case TEXT_VIEW_DRAWABLE_ACTION_TAG:
-                            mActions.add(new TextViewDrawableAction(parcel));
-                            break;
-                        case TEXT_VIEW_SIZE_ACTION_TAG:
-                            mActions.add(new TextViewSizeAction(parcel));
-                            break;
-                        case VIEW_PADDING_ACTION_TAG:
-                            mActions.add(new ViewPaddingAction(parcel));
-                            break;
-                        case BITMAP_REFLECTION_ACTION_TAG:
-                            mActions.add(new BitmapReflectionAction(parcel));
-                            break;
-                        case SET_REMOTE_VIEW_ADAPTER_LIST_TAG:
-                            mActions.add(new SetRemoteViewsAdapterList(parcel));
-                            break;
-                        case TEXT_VIEW_DRAWABLE_COLOR_FILTER_ACTION_TAG:
-                            mActions.add(new TextViewDrawableColorFilterAction(parcel));
-                            break;
-                        case SET_REMOTE_INPUTS_ACTION_TAG:
-                            mActions.add(new SetRemoteInputsAction(parcel));
-                            break;
-                        case LAYOUT_PARAM_ACTION_TAG:
-                            mActions.add(new LayoutParamAction(parcel));
-                            break;
-                        case OVERRIDE_TEXT_COLORS_TAG:
-                            mActions.add(new OverrideTextColorsAction(parcel));
-                            break;
-                        default:
-                            throw new ActionException("Tag " + tag + " not found");
-                    }
+                mActions = new ArrayList<>(count);
+                for (int i = 0; i < count; i++) {
+                    mActions.add(getActionFromParcel(parcel, depth));
                 }
             }
         } else {
@@ -2512,40 +2407,69 @@
             mLayoutId = mPortrait.getLayoutId();
         }
         mReapplyDisallowed = parcel.readInt() == 0;
-
-        // setup the memory usage statistics
-        mMemoryUsageCounter = new MemoryUsageCounter();
-        recalculateMemoryUsage();
     }
 
+    private Action getActionFromParcel(Parcel parcel, int depth) {
+        int tag = parcel.readInt();
+        switch (tag) {
+            case SET_ON_CLICK_PENDING_INTENT_TAG:
+                return new SetOnClickPendingIntent(parcel);
+            case SET_DRAWABLE_PARAMETERS_TAG:
+                return new SetDrawableParameters(parcel);
+            case REFLECTION_ACTION_TAG:
+                return new ReflectionAction(parcel);
+            case VIEW_GROUP_ACTION_ADD_TAG:
+                return new ViewGroupActionAdd(parcel, mBitmapCache, mApplication, depth);
+            case VIEW_GROUP_ACTION_REMOVE_TAG:
+                return new ViewGroupActionRemove(parcel);
+            case SET_REFLECTION_ACTION_WITHOUT_PARAMS_TAG:
+                return new ReflectionActionWithoutParams(parcel);
+            case SET_EMPTY_VIEW_ACTION_TAG:
+                return new SetEmptyView(parcel);
+            case SET_PENDING_INTENT_TEMPLATE_TAG:
+                return new SetPendingIntentTemplate(parcel);
+            case SET_ON_CLICK_FILL_IN_INTENT_TAG:
+                return new SetOnClickFillInIntent(parcel);
+            case SET_REMOTE_VIEW_ADAPTER_INTENT_TAG:
+                return new SetRemoteViewsAdapterIntent(parcel);
+            case TEXT_VIEW_DRAWABLE_ACTION_TAG:
+                return new TextViewDrawableAction(parcel);
+            case TEXT_VIEW_SIZE_ACTION_TAG:
+                return new TextViewSizeAction(parcel);
+            case VIEW_PADDING_ACTION_TAG:
+                return new ViewPaddingAction(parcel);
+            case BITMAP_REFLECTION_ACTION_TAG:
+                return new BitmapReflectionAction(parcel);
+            case SET_REMOTE_VIEW_ADAPTER_LIST_TAG:
+                return new SetRemoteViewsAdapterList(parcel);
+            case TEXT_VIEW_DRAWABLE_COLOR_FILTER_ACTION_TAG:
+                return new TextViewDrawableColorFilterAction(parcel);
+            case SET_REMOTE_INPUTS_ACTION_TAG:
+                return new SetRemoteInputsAction(parcel);
+            case LAYOUT_PARAM_ACTION_TAG:
+                return new LayoutParamAction(parcel);
+            case OVERRIDE_TEXT_COLORS_TAG:
+                return new OverrideTextColorsAction(parcel);
+            default:
+                throw new ActionException("Tag " + tag + " not found");
+        }
+    };
+
     /**
      * Returns a deep copy of the RemoteViews object. The RemoteView may not be
      * attached to another RemoteView -- it must be the root of a hierarchy.
      *
+     * @deprecated use {@link #RemoteViews(RemoteViews)} instead.
      * @throws IllegalStateException if this is not the root of a RemoteView
      *         hierarchy
      */
     @Override
+    @Deprecated
     public RemoteViews clone() {
-        synchronized (this) {
-            Preconditions.checkState(mIsRoot, "RemoteView has been attached to another RemoteView. "
-                    + "May only clone the root of a RemoteView hierarchy.");
+        Preconditions.checkState(mIsRoot, "RemoteView has been attached to another RemoteView. "
+                + "May only clone the root of a RemoteView hierarchy.");
 
-            Parcel p = Parcel.obtain();
-
-            // Do not parcel the Bitmap cache - doing so creates an expensive copy of all bitmaps.
-            // Instead pretend we're not owning the cache while parceling.
-            mIsRoot = false;
-            writeToParcel(p, PARCELABLE_ELIDE_DUPLICATES);
-            p.setDataPosition(0);
-            mIsRoot = true;
-
-            RemoteViews rv = new RemoteViews(p, mBitmapCache.clone(), mApplication, 0);
-            rv.mIsRoot = true;
-
-            p.recycle();
-            return rv;
-        }
+        return new RemoteViews(this);
     }
 
     public String getPackage() {
@@ -2575,30 +2499,6 @@
     }
 
     /**
-     * Updates the memory usage statistics.
-     */
-    private void recalculateMemoryUsage() {
-        mMemoryUsageCounter.clear();
-
-        if (!hasLandscapeAndPortraitLayouts()) {
-            // Accumulate the memory usage for each action
-            if (mActions != null) {
-                final int count = mActions.size();
-                for (int i= 0; i < count; ++i) {
-                    mActions.get(i).updateMemoryUsageEstimate(mMemoryUsageCounter);
-                }
-            }
-            if (mIsRoot) {
-                mBitmapCache.addBitmapMemory(mMemoryUsageCounter);
-            }
-        } else {
-            mMemoryUsageCounter.increment(mLandscape.estimateMemoryUsage());
-            mMemoryUsageCounter.increment(mPortrait.estimateMemoryUsage());
-            mBitmapCache.addBitmapMemory(mMemoryUsageCounter);
-        }
-    }
-
-    /**
      * Recursively sets BitmapCache in the hierarchy and update the bitmap ids.
      */
     private void setBitmapCache(BitmapCache bitmapCache) {
@@ -2621,7 +2521,7 @@
      */
     /** @hide */
     public int estimateMemoryUsage() {
-        return mMemoryUsageCounter.getMemoryUsage();
+        return mBitmapCache.getBitmapMemory();
     }
 
     /**
@@ -2636,12 +2536,9 @@
                     " portrait layouts individually before constructing the combined layout.");
         }
         if (mActions == null) {
-            mActions = new ArrayList<Action>();
+            mActions = new ArrayList<>();
         }
         mActions.add(a);
-
-        // update the memory usage stats
-        a.updateMemoryUsageEstimate(mMemoryUsageCounter);
     }
 
     /**
diff --git a/core/tests/coretests/src/android/widget/RemoteViewsTest.java b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
index bf994a9..d26437e 100644
--- a/core/tests/coretests/src/android/widget/RemoteViewsTest.java
+++ b/core/tests/coretests/src/android/widget/RemoteViewsTest.java
@@ -16,6 +16,10 @@
 
 package android.widget;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.drawable.BitmapDrawable;
@@ -36,10 +40,6 @@
 import org.junit.rules.ExpectedException;
 import org.junit.runner.RunWith;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertTrue;
-
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
@@ -336,7 +336,9 @@
             parent.addView(R.id.layout, views);
             views = parent;
         }
+        // Both clone and parcel/unparcel work,
         views.clone();
+        parcelAndRecreate(views);
 
         views = new RemoteViews(mPackage, R.layout.remote_views_test);
         for (int i = 0; i < 11; i++) {
@@ -344,8 +346,10 @@
             parent.addView(R.id.layout, views);
             views = parent;
         }
-        exception.expect(IllegalArgumentException.class);
+        // Clone works but parcel/unparcel fails
         views.clone();
+        exception.expect(IllegalArgumentException.class);
+        parcelAndRecreate(views);
     }
 
     @Test
@@ -355,15 +359,27 @@
             views = new RemoteViews(views,
                     new RemoteViews(mPackage, R.layout.remote_views_test));
         }
+        // Both clone and parcel/unparcel work,
         views.clone();
+        parcelAndRecreate(views);
 
         views = new RemoteViews(mPackage, R.layout.remote_views_test);
         for (int i = 0; i < 11; i++) {
-            RemoteViews parent = new RemoteViews(mPackage, R.layout.remote_views_test);
-            parent.addView(R.id.layout, views);
-            views = parent;
+            views = new RemoteViews(views,
+                    new RemoteViews(mPackage, R.layout.remote_views_test));
         }
-        exception.expect(IllegalArgumentException.class);
+        // Clone works but parcel/unparcel fails
         views.clone();
+        exception.expect(IllegalArgumentException.class);
+        parcelAndRecreate(views);
+    }
+
+    private void parcelAndRecreate(RemoteViews views) {
+        Parcel p = Parcel.obtain();
+        views.writeToParcel(p, 0);
+        p.setDataPosition(0);
+
+        RemoteViews.CREATOR.createFromParcel(p);
+        p.recycle();
     }
 }