Merge "Fix crash with animation specs"
diff --git a/api/current.txt b/api/current.txt
index cca8293..6208640 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -4795,7 +4795,7 @@
     method public android.graphics.drawable.Icon getLargeIcon();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
-    method public android.app.Notification.Topic[] getTopics();
+    method public android.app.Notification.Topic getTopic();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -4960,7 +4960,6 @@
     method public android.app.Notification.Builder addAction(android.app.Notification.Action);
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
-    method public android.app.Notification.Builder addTopic(android.app.Notification.Topic);
     method public android.app.Notification build();
     method public android.app.Notification.Builder extend(android.app.Notification.Extender);
     method public android.os.Bundle getExtras();
@@ -5009,6 +5008,7 @@
     method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
     method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
     method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
+    method public android.app.Notification.Builder setTopic(android.app.Notification.Topic);
     method public android.app.Notification.Builder setUsesChronometer(boolean);
     method public android.app.Notification.Builder setVibrate(long[]);
     method public android.app.Notification.Builder setVisibility(int);
@@ -5166,10 +5166,12 @@
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
-    ctor public NotificationManager.Policy(int, int, int);
+    ctor public deprecated NotificationManager.Policy(int, int, int);
+    ctor public NotificationManager.Policy(int, int, int, int);
     method public int describeContents();
     method public static java.lang.String priorityCategoriesToString(int);
     method public static java.lang.String prioritySendersToString(int);
+    method public static java.lang.String suppressedEffectsToString(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR;
     field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8
@@ -5180,9 +5182,13 @@
     field public static final int PRIORITY_SENDERS_ANY = 0; // 0x0
     field public static final int PRIORITY_SENDERS_CONTACTS = 1; // 0x1
     field public static final int PRIORITY_SENDERS_STARRED = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
+    field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
+    field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
     field public final int priorityCallSenders;
     field public final int priorityCategories;
     field public final int priorityMessageSenders;
+    field public final int suppressedVisualEffects;
   }
 
   public final class PendingIntent implements android.os.Parcelable {
@@ -28994,12 +29000,15 @@
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
+    field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
+    field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
   }
 
   public static class NotificationListenerService.Ranking {
     ctor public NotificationListenerService.Ranking();
     method public java.lang.String getKey();
     method public int getRank();
+    method public int getSuppressedVisualEffects();
     method public boolean isAmbient();
     method public boolean matchesInterruptionFilter();
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index 3946d4a..fc11f34 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -4913,7 +4913,7 @@
     method public android.graphics.drawable.Icon getLargeIcon();
     method public android.graphics.drawable.Icon getSmallIcon();
     method public java.lang.String getSortKey();
-    method public android.app.Notification.Topic[] getTopics();
+    method public android.app.Notification.Topic getTopic();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.media.AudioAttributes AUDIO_ATTRIBUTES_DEFAULT;
     field public static final java.lang.String CATEGORY_ALARM = "alarm";
@@ -5078,7 +5078,6 @@
     method public android.app.Notification.Builder addAction(android.app.Notification.Action);
     method public android.app.Notification.Builder addExtras(android.os.Bundle);
     method public android.app.Notification.Builder addPerson(java.lang.String);
-    method public android.app.Notification.Builder addTopic(android.app.Notification.Topic);
     method public android.app.Notification build();
     method public android.app.Notification.Builder extend(android.app.Notification.Extender);
     method public android.os.Bundle getExtras();
@@ -5127,6 +5126,7 @@
     method public android.app.Notification.Builder setSubText(java.lang.CharSequence);
     method public android.app.Notification.Builder setTicker(java.lang.CharSequence);
     method public deprecated android.app.Notification.Builder setTicker(java.lang.CharSequence, android.widget.RemoteViews);
+    method public android.app.Notification.Builder setTopic(android.app.Notification.Topic);
     method public android.app.Notification.Builder setUsesChronometer(boolean);
     method public android.app.Notification.Builder setVibrate(long[]);
     method public android.app.Notification.Builder setVisibility(int);
@@ -5284,10 +5284,12 @@
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
-    ctor public NotificationManager.Policy(int, int, int);
+    ctor public deprecated NotificationManager.Policy(int, int, int);
+    ctor public NotificationManager.Policy(int, int, int, int);
     method public int describeContents();
     method public static java.lang.String priorityCategoriesToString(int);
     method public static java.lang.String prioritySendersToString(int);
+    method public static java.lang.String suppressedEffectsToString(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.NotificationManager.Policy> CREATOR;
     field public static final int PRIORITY_CATEGORY_CALLS = 8; // 0x8
@@ -5298,9 +5300,13 @@
     field public static final int PRIORITY_SENDERS_ANY = 0; // 0x0
     field public static final int PRIORITY_SENDERS_CONTACTS = 1; // 0x1
     field public static final int PRIORITY_SENDERS_STARRED = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
+    field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
+    field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
     field public final int priorityCallSenders;
     field public final int priorityCategories;
     field public final int priorityMessageSenders;
+    field public final int suppressedVisualEffects;
   }
 
   public final class PendingIntent implements android.os.Parcelable {
@@ -31113,6 +31119,8 @@
     field public static final int INTERRUPTION_FILTER_PRIORITY = 2; // 0x2
     field public static final int INTERRUPTION_FILTER_UNKNOWN = 0; // 0x0
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
+    field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
+    field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
     field public static final int TRIM_FULL = 0; // 0x0
     field public static final int TRIM_LIGHT = 1; // 0x1
   }
@@ -31121,6 +31129,7 @@
     ctor public NotificationListenerService.Ranking();
     method public java.lang.String getKey();
     method public int getRank();
+    method public int getSuppressedVisualEffects();
     method public boolean isAmbient();
     method public boolean matchesInterruptionFilter();
   }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0b77be3..b5b77e6 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -1466,10 +1466,10 @@
                 };
     }
 
-    private Topic[] topics;
+    private Topic topic;
 
-    public Topic[] getTopics() {
-        return topics;
+    public Topic getTopic() {
+        return topic;
     }
 
     /**
@@ -1599,7 +1599,9 @@
 
         color = parcel.readInt();
 
-        topics = parcel.createTypedArray(Topic.CREATOR); // may be null
+        if (parcel.readInt() != 0) {
+            topic = Topic.CREATOR.createFromParcel(parcel);
+        }
     }
 
     @Override
@@ -1700,11 +1702,8 @@
 
         that.color = this.color;
 
-        if (this.topics != null) {
-            that.topics = new Topic[this.topics.length];
-            for(int i=0; i<this.topics.length; i++) {
-                that.topics[i] = this.topics[i].clone();
-            }
+        if (this.topic != null) {
+            that.topic = this.topic.clone();
         }
 
         if (!heavy) {
@@ -1878,7 +1877,12 @@
 
         parcel.writeInt(color);
 
-        parcel.writeTypedArray(topics, 0); // null ok
+        if (topic != null) {
+            parcel.writeInt(1);
+            topic.writeToParcel(parcel, 0);
+        } else {
+            parcel.writeInt(0);
+        }
     }
 
     /**
@@ -2008,17 +2012,9 @@
             sb.append(" publicVersion=");
             sb.append(publicVersion.toString());
         }
-        if (topics != null) {
-            sb.append("topics=[");
-            int N = topics.length;
-            if (N > 0) {
-                for (int i = 0; i < N-1; i++) {
-                    sb.append(topics[i]);
-                    sb.append(',');
-                }
-                sb.append(topics[N-1]);
-            }
-            sb.append("]");
+        if (topic != null) {
+            sb.append("topic=");
+            sb.append(topic.toString());
         }
         sb.append(")");
         return sb.toString();
@@ -2136,7 +2132,6 @@
         private ArrayList<String> mPersonList = new ArrayList<String>();
         private NotificationColorUtil mColorUtil;
         private boolean mColorUtilInited = false;
-        private List<Topic> mTopics = new ArrayList<>();
 
         /**
          * The user that built the notification originally.
@@ -2187,10 +2182,6 @@
                     Collections.addAll(mPersonList, mN.extras.getStringArray(EXTRA_PEOPLE));
                 }
 
-                if (mN.getTopics() != null) {
-                    Collections.addAll(mTopics, mN.getTopics());
-                }
-
                 String templateClass = mN.extras.getString(EXTRA_TEMPLATE);
                 if (!TextUtils.isEmpty(templateClass)) {
                     final Class<? extends Style> styleClass
@@ -2962,15 +2953,15 @@
         }
 
         /**
-         * Add a topic to this notification. Topics are typically displayed in Notification
+         * Sets the topic of this notification. Topics are typically displayed in Notification
          * settings.
          * <p>
          * Every topic must have an id and a textual label.
          *
          * @param topic The topic to add.
          */
-        public Builder addTopic(Topic topic) {
-            mTopics.add(topic);
+        public Builder setTopic(Topic topic) {
+            mN.topic = topic;
             return this;
         }
 
@@ -3452,10 +3443,6 @@
                 mN.extras.putStringArray(EXTRA_PEOPLE,
                         mPersonList.toArray(new String[mPersonList.size()]));
             }
-            if (mTopics.size() > 0) {
-                mN.topics = new Topic[mTopics.size()];
-                mTopics.toArray(mN.topics);
-            }
             return mN;
         }
 
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 07b4d39..043c503 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -610,15 +610,39 @@
          * PRIORITY_SENDERS_ANY, PRIORITY_SENDERS_CONTACTS, PRIORITY_SENDERS_STARRED */
         public final int priorityMessageSenders;
 
+        public static final int SUPPRESSED_EFFECTS_UNSET = -1;
+        public static final int SUPPRESSED_EFFECT_LIGHTS = 1 << 0;
+        public static final int SUPPRESSED_EFFECT_PEEK = 1 << 1;
+
+        private static final int[] ALL_SUPPRESSED_EFFECTS = {
+                SUPPRESSED_EFFECT_LIGHTS,
+                SUPPRESSED_EFFECT_PEEK,
+        };
+
+        /**
+         * Visual effects to suppress for a notification that is filtered by Do Not Disturb mode.
+         * Bitmask of SUPPRESSED_EFFECT_* constants.
+         */
+        public final int suppressedVisualEffects;
+
+
+        @Deprecated
         public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders) {
+            this(priorityCategories, priorityCallSenders, priorityMessageSenders,
+                    SUPPRESSED_EFFECTS_UNSET);
+        }
+
+        public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders,
+                int suppressedVisualEffects) {
             this.priorityCategories = priorityCategories;
             this.priorityCallSenders = priorityCallSenders;
             this.priorityMessageSenders = priorityMessageSenders;
+            this.suppressedVisualEffects = suppressedVisualEffects;
         }
 
         /** @hide */
         public Policy(Parcel source) {
-            this(source.readInt(), source.readInt(), source.readInt());
+            this(source.readInt(), source.readInt(), source.readInt(), source.readInt());
         }
 
         @Override
@@ -626,6 +650,7 @@
             dest.writeInt(priorityCategories);
             dest.writeInt(priorityCallSenders);
             dest.writeInt(priorityMessageSenders);
+            dest.writeInt(suppressedVisualEffects);
         }
 
         @Override
@@ -635,7 +660,8 @@
 
         @Override
         public int hashCode() {
-            return Objects.hash(priorityCategories, priorityCallSenders, priorityMessageSenders);
+            return Objects.hash(priorityCategories, priorityCallSenders, priorityMessageSenders,
+                    suppressedVisualEffects);
         }
 
         @Override
@@ -645,7 +671,8 @@
             final Policy other = (Policy) o;
             return other.priorityCategories == priorityCategories
                     && other.priorityCallSenders == priorityCallSenders
-                    && other.priorityMessageSenders == priorityMessageSenders;
+                    && other.priorityMessageSenders == priorityMessageSenders
+                    && other.suppressedVisualEffects == suppressedVisualEffects;
         }
 
         @Override
@@ -654,9 +681,29 @@
                     + "priorityCategories=" + priorityCategoriesToString(priorityCategories)
                     + ",priorityCallSenders=" + prioritySendersToString(priorityCallSenders)
                     + ",priorityMessageSenders=" + prioritySendersToString(priorityMessageSenders)
+                    + ",suppressedVisualEffects="
+                    + suppressedEffectsToString(suppressedVisualEffects)
                     + "]";
         }
 
+        public static String suppressedEffectsToString(int effects) {
+            if (effects <= 0) return "";
+            final StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < ALL_SUPPRESSED_EFFECTS.length; i++) {
+                final int effect = ALL_SUPPRESSED_EFFECTS[i];
+                if ((effects & effect) != 0) {
+                    if (sb.length() > 0) sb.append(',');
+                    sb.append(effectToString(effect));
+                }
+                effects &= ~effect;
+            }
+            if (effects != 0) {
+                if (sb.length() > 0) sb.append(',');
+                sb.append("UNKNOWN_").append(effects);
+            }
+            return sb.toString();
+        }
+
         public static String priorityCategoriesToString(int priorityCategories) {
             if (priorityCategories == 0) return "";
             final StringBuilder sb = new StringBuilder();
@@ -675,6 +722,15 @@
             return sb.toString();
         }
 
+        private static String effectToString(int effect) {
+            switch (effect) {
+                case SUPPRESSED_EFFECT_LIGHTS: return "SUPPRESSED_EFFECT_LIGHTS";
+                case SUPPRESSED_EFFECT_PEEK: return "SUPPRESSED_EFFECT_PEEK";
+                case SUPPRESSED_EFFECTS_UNSET: return "SUPPRESSED_EFFECTS_UNSET";
+                default: return "UNKNOWN_" + effect;
+            }
+        }
+
         private static String priorityCategoryToString(int priorityCategory) {
             switch (priorityCategory) {
                 case PRIORITY_CATEGORY_REMINDERS: return "PRIORITY_CATEGORY_REMINDERS";
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index b627641..48359d47 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -144,4 +144,18 @@
             return sInstance;
         }
     }
+
+    /** @hide */
+    public static ApplicationConfig getPlatformDefault() {
+        return new ApplicationConfig(new ConfigSource() {
+            @Override
+            public NetworkSecurityConfig getDefaultConfig() {
+                return NetworkSecurityConfig.DEFAULT;
+            }
+            @Override
+            public Set<Pair<Domain, NetworkSecurityConfig>> getPerDomainConfigs() {
+                return null;
+            }
+        });
+    }
 }
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 8906f9b..9eab80c 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -16,11 +16,14 @@
 
 package android.security.net.config;
 
+import android.util.ArrayMap;
 import android.util.ArraySet;
+import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 import javax.net.ssl.X509TrustManager;
@@ -57,12 +60,24 @@
             if (mAnchors != null) {
                 return mAnchors;
             }
-            Set<TrustAnchor> anchors = new ArraySet<TrustAnchor>();
+            // Merge trust anchors based on the X509Certificate.
+            // If we see the same certificate in two TrustAnchors, one with overridesPins and one
+            // without, the one with overridesPins wins.
+            Map<X509Certificate, TrustAnchor> anchorMap = new ArrayMap<>();
             for (CertificatesEntryRef ref : mCertificatesEntryRefs) {
-                anchors.addAll(ref.getTrustAnchors());
+                Set<TrustAnchor> anchors = ref.getTrustAnchors();
+                for (TrustAnchor anchor : anchors) {
+                    if (anchor.overridesPins) {
+                        anchorMap.put(anchor.certificate, anchor);
+                    } else if (!anchorMap.containsKey(anchor.certificate)) {
+                        anchorMap.put(anchor.certificate, anchor);
+                    }
+                }
             }
+            ArraySet<TrustAnchor> anchors = new ArraySet<TrustAnchor>(anchorMap.size());
+            anchors.addAll(anchorMap.values());
             mAnchors = anchors;
-            return anchors;
+            return mAnchors;
         }
     }
 
diff --git a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
index ca8cdae..ac762ef 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
@@ -16,13 +16,21 @@
 
 package android.security.net.config;
 
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+import java.security.Security;
 import java.security.Provider;
 
 /** @hide */
 public final class NetworkSecurityConfigProvider extends Provider {
-
-    private static String PREFIX =
+    private static final String LOG_TAG = "NetworkSecurityConfig";
+    private static final String PREFIX =
             NetworkSecurityConfigProvider.class.getPackage().getName() + ".";
+    public static final String META_DATA_NETWORK_SECURITY_CONFIG =
+            "android.security.net.config";
+    private static final boolean DBG = true;
 
     public NetworkSecurityConfigProvider() {
         // TODO: More clever name than this
@@ -30,4 +38,43 @@
         put("TrustManagerFactory.PKIX", PREFIX + "RootTrustManagerFactorySpi");
         put("Alg.Alias.TrustManagerFactory.X509", "PKIX");
     }
+
+    public static void install(Context context) {
+        ApplicationInfo info = null;
+        // TODO: This lookup shouldn't be done in the app startup path, it should be done lazily.
+        try {
+            info = context.getPackageManager().getApplicationInfo(context.getPackageName(),
+                    PackageManager.GET_META_DATA);
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new RuntimeException("Failed to look up ApplicationInfo", e);
+        }
+        int configResourceId = 0;
+        if (info != null && info.metaData != null) {
+            configResourceId = info.metaData.getInt(META_DATA_NETWORK_SECURITY_CONFIG);
+        }
+
+        ApplicationConfig config;
+        if (configResourceId != 0) {
+            boolean debugBuild = (info.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+            if (DBG) {
+                Log.d(LOG_TAG, "Using Network Security Config from resource "
+                        + context.getResources().getResourceEntryName(configResourceId)
+                        + " debugBuild: " + debugBuild);
+            }
+            ConfigSource source = new XmlConfigSource(context, configResourceId, debugBuild);
+            config = new ApplicationConfig(source);
+        } else {
+            if (DBG) {
+                Log.d(LOG_TAG, "No Network Security Config specified, using platform default");
+            }
+            config = ApplicationConfig.getPlatformDefault();
+        }
+
+        ApplicationConfig.setDefaultInstance(config);
+        int pos = Security.insertProviderAt(new NetworkSecurityConfigProvider(), 1);
+        if (pos != 1) {
+            throw new RuntimeException("Failed to install provider as highest priority provider."
+                    + " Provider was installed at position " + pos);
+        }
+    }
 }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 7e7b5fc..ee97e8e 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -108,6 +108,11 @@
      * This does not change the interruption filter, only the effects. **/
     public static final int HINT_HOST_DISABLE_EFFECTS = 1;
 
+    public static final int SUPPRESSED_EFFECT_LIGHTS =
+            NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+    public static final int SUPPRESSED_EFFECT_PEEK =
+            NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+
     /**
      * The full trim of the StatusBarNotification including all its features.
      *
@@ -822,6 +827,7 @@
         private boolean mIsAmbient;
         private boolean mMatchesInterruptionFilter;
         private int mVisibilityOverride;
+        private int mSuppressedVisualEffects;
 
         public Ranking() {}
 
@@ -861,6 +867,14 @@
             return mVisibilityOverride;
         }
 
+        /**
+         * Returns the type(s) of visual effects that should be suppressed for this notification.
+         * See {@link #SUPPRESSED_EFFECT_LIGHTS}, {@link #SUPPRESSED_EFFECT_PEEK}}.
+         */
+        public int getSuppressedVisualEffects() {
+            return mSuppressedVisualEffects;
+        }
+
 
         /**
          * Returns whether the notification matches the user's interruption
@@ -874,12 +888,14 @@
         }
 
         private void populate(String key, int rank, boolean isAmbient,
-                boolean matchesInterruptionFilter, int visibilityOverride) {
+                boolean matchesInterruptionFilter, int visibilityOverride,
+                int suppressedVisualEffects) {
             mKey = key;
             mRank = rank;
             mIsAmbient = isAmbient;
             mMatchesInterruptionFilter = matchesInterruptionFilter;
             mVisibilityOverride = visibilityOverride;
+            mSuppressedVisualEffects = suppressedVisualEffects;
         }
     }
 
@@ -896,6 +912,7 @@
         private ArrayMap<String,Integer> mRanks;
         private ArraySet<Object> mIntercepted;
         private ArrayMap<String, Integer> mVisibilityOverrides;
+        private ArrayMap<String, Integer> mSuppressedVisualEffects;
 
         private RankingMap(NotificationRankingUpdate rankingUpdate) {
             mRankingUpdate = rankingUpdate;
@@ -921,7 +938,7 @@
         public boolean getRanking(String key, Ranking outRanking) {
             int rank = getRank(key);
             outRanking.populate(key, rank, isAmbient(key), !isIntercepted(key),
-                    getVisibilityOverride(key));
+                    getVisibilityOverride(key), getSuppressedVisualEffects(key));
             return rank >= 0;
         }
 
@@ -959,11 +976,24 @@
                     buildVisibilityOverridesLocked();
                 }
             }
-            Integer overide = mVisibilityOverrides.get(key);
-            if (overide == null) {
+            Integer override = mVisibilityOverrides.get(key);
+            if (override == null) {
                 return Ranking.VISIBILITY_NO_OVERRIDE;
             }
-            return overide.intValue();
+            return override.intValue();
+        }
+
+        private int getSuppressedVisualEffects(String key) {
+            synchronized (this) {
+                if (mSuppressedVisualEffects == null) {
+                    buildSuppressedVisualEffectsLocked();
+                }
+            }
+            Integer suppressed = mSuppressedVisualEffects.get(key);
+            if (suppressed == null) {
+                return 0;
+            }
+            return suppressed.intValue();
         }
 
         // Locked by 'this'
@@ -992,6 +1022,15 @@
             }
         }
 
+        // Locked by 'this'
+        private void buildSuppressedVisualEffectsLocked() {
+            Bundle suppressedBundle = mRankingUpdate.getSuppressedVisualEffects();
+            mSuppressedVisualEffects = new ArrayMap<>(suppressedBundle.size());
+            for (String key: suppressedBundle.keySet()) {
+                mSuppressedVisualEffects.put(key, suppressedBundle.getInt(key));
+            }
+        }
+
         // ----------- Parcelable
 
         @Override
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index 6fba900..1282fb1 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -28,13 +28,15 @@
     private final String[] mInterceptedKeys;
     private final int mFirstAmbientIndex;
     private final Bundle mVisibilityOverrides;
+    private final Bundle mSuppressedVisualEffects;
 
     public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
-            Bundle visibilityOverrides, int firstAmbientIndex) {
+            Bundle visibilityOverrides, int firstAmbientIndex, Bundle suppressedVisualEffects) {
         mKeys = keys;
         mFirstAmbientIndex = firstAmbientIndex;
         mInterceptedKeys = interceptedKeys;
         mVisibilityOverrides = visibilityOverrides;
+        mSuppressedVisualEffects = suppressedVisualEffects;
     }
 
     public NotificationRankingUpdate(Parcel in) {
@@ -42,6 +44,7 @@
         mFirstAmbientIndex = in.readInt();
         mInterceptedKeys = in.readStringArray();
         mVisibilityOverrides = in.readBundle();
+        mSuppressedVisualEffects = in.readBundle();
     }
 
     @Override
@@ -55,6 +58,7 @@
         out.writeInt(mFirstAmbientIndex);
         out.writeStringArray(mInterceptedKeys);
         out.writeBundle(mVisibilityOverrides);
+        out.writeBundle(mSuppressedVisualEffects);
     }
 
     public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -83,4 +87,8 @@
     public Bundle getVisibilityOverrides() {
         return mVisibilityOverrides;
     }
+
+    public Bundle getSuppressedVisualEffects() {
+        return mSuppressedVisualEffects;
+    }
 }
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 82f1b28..b3399d0 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -77,6 +77,8 @@
     private static final boolean DEFAULT_ALLOW_REMINDERS = true;
     private static final boolean DEFAULT_ALLOW_EVENTS = true;
     private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
+    private static final boolean DEFAULT_ALLOW_PEEK = true;
+    private static final boolean DEFAULT_ALLOW_LIGHTS = true;
 
     private static final int XML_VERSION = 2;
     private static final String ZEN_TAG = "zen";
@@ -91,6 +93,8 @@
     private static final String ALLOW_ATT_MESSAGES_FROM = "messagesFrom";
     private static final String ALLOW_ATT_REMINDERS = "reminders";
     private static final String ALLOW_ATT_EVENTS = "events";
+    private static final String ALLOW_ATT_PEEK = "peek";
+    private static final String ALLOW_ATT_LIGHTS = "lights";
 
     private static final String CONDITION_TAG = "condition";
     private static final String CONDITION_ATT_COMPONENT = "component";
@@ -122,6 +126,8 @@
     public int allowCallsFrom = DEFAULT_SOURCE;
     public int allowMessagesFrom = DEFAULT_SOURCE;
     public int user = UserHandle.USER_SYSTEM;
+    public boolean allowPeek = DEFAULT_ALLOW_PEEK;
+    public boolean allowLights = DEFAULT_ALLOW_LIGHTS;
 
     public ZenRule manualRule;
     public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
@@ -148,6 +154,8 @@
                 automaticRules.put(ids[i], rules[i]);
             }
         }
+        allowPeek = source.readInt() == 1;
+        allowLights = source.readInt() == 1;
     }
 
     @Override
@@ -175,22 +183,26 @@
         } else {
             dest.writeInt(0);
         }
+        dest.writeInt(allowPeek ? 1 : 0);
+        dest.writeInt(allowLights ? 1 : 0);
     }
 
     @Override
     public String toString() {
         return new StringBuilder(ZenModeConfig.class.getSimpleName()).append('[')
-            .append("user=").append(user)
-            .append(",allowCalls=").append(allowCalls)
-            .append(",allowRepeatCallers=").append(allowRepeatCallers)
-            .append(",allowMessages=").append(allowMessages)
-            .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom))
-            .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
-            .append(",allowReminders=").append(allowReminders)
-            .append(",allowEvents=").append(allowEvents)
-            .append(",automaticRules=").append(automaticRules)
-            .append(",manualRule=").append(manualRule)
-            .append(']').toString();
+                .append("user=").append(user)
+                .append(",allowCalls=").append(allowCalls)
+                .append(",allowRepeatCallers=").append(allowRepeatCallers)
+                .append(",allowMessages=").append(allowMessages)
+                .append(",allowCallsFrom=").append(sourceToString(allowCallsFrom))
+                .append(",allowMessagesFrom=").append(sourceToString(allowMessagesFrom))
+                .append(",allowReminders=").append(allowReminders)
+                .append(",allowEvents=").append(allowEvents)
+                .append(",allowPeek=").append(allowPeek)
+                .append(",allowLights=").append(allowLights)
+                .append(",automaticRules=").append(automaticRules)
+                .append(",manualRule=").append(manualRule)
+                .append(']').toString();
     }
 
     private Diff diff(ZenModeConfig to) {
@@ -222,6 +234,12 @@
         if (allowEvents != to.allowEvents) {
             d.addLine("allowEvents", allowEvents, to.allowEvents);
         }
+        if (allowPeek != to.allowPeek) {
+            d.addLine("allowPeek", allowPeek, to.allowPeek);
+        }
+        if (allowLights != to.allowLights) {
+            d.addLine("allowLights", allowLights, to.allowLights);
+        }
         final ArraySet<String> allRules = new ArraySet<>();
         addKeys(allRules, automaticRules);
         addKeys(allRules, to.automaticRules);
@@ -319,6 +337,8 @@
                 && other.allowMessagesFrom == allowMessagesFrom
                 && other.allowReminders == allowReminders
                 && other.allowEvents == allowEvents
+                && other.allowPeek == allowPeek
+                && other.allowLights == allowLights
                 && other.user == user
                 && Objects.equals(other.automaticRules, automaticRules)
                 && Objects.equals(other.manualRule, manualRule);
@@ -327,7 +347,8 @@
     @Override
     public int hashCode() {
         return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowCallsFrom,
-                allowMessagesFrom, allowReminders, allowEvents, user, automaticRules, manualRule);
+                allowMessagesFrom, allowReminders, allowEvents, allowPeek, allowLights,
+                user, automaticRules, manualRule);
     }
 
     private static String toDayList(int[] days) {
@@ -412,6 +433,8 @@
                         rt.allowCallsFrom = DEFAULT_SOURCE;
                         rt.allowMessagesFrom = DEFAULT_SOURCE;
                     }
+                    rt.allowPeek = safeBoolean(parser, ALLOW_ATT_PEEK, DEFAULT_ALLOW_PEEK);
+                    rt.allowLights = safeBoolean(parser, ALLOW_ATT_LIGHTS, DEFAULT_ALLOW_LIGHTS);
                 } else if (MANUAL_TAG.equals(tag)) {
                     rt.manualRule = readRuleXml(parser);
                 } else if (AUTOMATIC_TAG.equals(tag)) {
@@ -440,6 +463,8 @@
         out.attribute(null, ALLOW_ATT_EVENTS, Boolean.toString(allowEvents));
         out.attribute(null, ALLOW_ATT_CALLS_FROM, Integer.toString(allowCallsFrom));
         out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
+        out.attribute(null, ALLOW_ATT_PEEK, Boolean.toString(allowPeek));
+        out.attribute(null, ALLOW_ATT_LIGHTS, Boolean.toString(allowLights));
         out.endTag(null, ALLOW_TAG);
 
         if (manualRule != null) {
@@ -611,9 +636,17 @@
         if (allowRepeatCallers) {
             priorityCategories |= Policy.PRIORITY_CATEGORY_REPEAT_CALLERS;
         }
+        int suppressedVisualEffects = 0;
+        if (!allowPeek) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_PEEK;
+        }
+        if (!allowLights) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
+        }
         priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders);
         priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders);
-        return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders);
+        return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
+                suppressedVisualEffects);
     }
 
     private static int sourceToPrioritySenders(int source, int def) {
@@ -645,6 +678,10 @@
         allowCallsFrom = prioritySendersToSource(policy.priorityCallSenders, allowCallsFrom);
         allowMessagesFrom = prioritySendersToSource(policy.priorityMessageSenders,
                 allowMessagesFrom);
+        if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
+            allowPeek = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) == 0;
+            allowLights = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) == 0;
+        }
     }
 
     public static Condition toTimeCondition(Context context, int minutesFromNow, int userHandle) {
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 88e9a95..b61706e 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -24,6 +24,7 @@
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.graphics.Bitmap;
+import android.graphics.drawable.AnimationDrawable;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Parcel;
@@ -142,6 +143,10 @@
     private Bitmap mBitmap;
     private float mHotSpotX;
     private float mHotSpotY;
+    // The bitmaps for the additional frame of animated pointer icon. Note that the first frame
+    // will be stored in mBitmap.
+    private Bitmap mBitmapFrames[];
+    private int mDurationPerFrame;
 
     private PointerIcon(int style) {
         mStyle = style;
@@ -472,6 +477,36 @@
         } else {
             drawable = context.getDrawable(bitmapRes);
         }
+        if (drawable instanceof AnimationDrawable) {
+            // Extract animation frame bitmaps.
+            final AnimationDrawable animationDrawable = (AnimationDrawable) drawable;
+            final int frames = animationDrawable.getNumberOfFrames();
+            drawable = animationDrawable.getFrame(0);
+            if (frames == 1) {
+                Log.w(TAG, "Animation icon with single frame -- simply treating the first "
+                        + "frame as a normal bitmap icon.");
+            } else {
+                // Assumes they have the exact duration.
+                mDurationPerFrame = animationDrawable.getDuration(0);
+                mBitmapFrames = new Bitmap[frames - 1];
+                final int width = drawable.getIntrinsicWidth();
+                final int height = drawable.getIntrinsicHeight();
+                for (int i = 1; i < frames; ++i) {
+                    Drawable drawableFrame = animationDrawable.getFrame(i);
+                    if (!(drawableFrame instanceof BitmapDrawable)) {
+                        throw new IllegalArgumentException("Frame of an animated pointer icon "
+                                + "must refer to a bitmap drawable.");
+                    }
+                    if (drawableFrame.getIntrinsicWidth() != width ||
+                        drawableFrame.getIntrinsicHeight() != height) {
+                        throw new IllegalArgumentException("The bitmap size of " + i + "-th frame "
+                                + "is different. All frames should have the exact same size and "
+                                + "share the same hotspot.");
+                    }
+                    mBitmapFrames[i - 1] = ((BitmapDrawable)drawableFrame).getBitmap();
+                }
+            }
+        }
         if (!(drawable instanceof BitmapDrawable)) {
             throw new IllegalArgumentException("<pointer-icon> bitmap attribute must "
                     + "refer to a bitmap drawable.");
@@ -509,8 +544,7 @@
             case STYLE_HELP:
                 return com.android.internal.R.styleable.Pointer_pointerIconHelp;
             case STYLE_WAIT:
-                // falls back to the default icon because no animation support.
-                return com.android.internal.R.styleable.Pointer_pointerIconArrow;
+                return com.android.internal.R.styleable.Pointer_pointerIconWait;
             case STYLE_CELL:
                 return com.android.internal.R.styleable.Pointer_pointerIconCell;
             case STYLE_CROSSHAIR:
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 461506b..de4d439 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6329,8 +6329,8 @@
 
         position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
 
-        outRect.set((int) (position.left + 0.5f), (int) (position.top + 0.5f),
-                (int) (position.right + 0.5f), (int) (position.bottom + 0.5f));
+        outRect.set(Math.round(position.left), Math.round(position.top),
+                Math.round(position.right), Math.round(position.bottom));
     }
 
     /**
@@ -18548,8 +18548,8 @@
             position[1] -= vr.mCurScrollY;
         }
 
-        inOutLocation[0] = (int) (position[0] + 0.5f);
-        inOutLocation[1] = (int) (position[1] + 0.5f);
+        inOutLocation[0] = Math.round(position[0]);
+        inOutLocation[1] = Math.round(position[1]);
     }
 
     /**
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index db978a6..25df004 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5114,10 +5114,10 @@
                     transformMatrix = childMatrix;
                 }
                 transformMatrix.mapRect(boundingRect);
-                dirty.set((int) (boundingRect.left - 0.5f),
-                        (int) (boundingRect.top - 0.5f),
-                        (int) (boundingRect.right + 0.5f),
-                        (int) (boundingRect.bottom + 0.5f));
+                dirty.set((int) Math.floor(boundingRect.left),
+                        (int) Math.floor(boundingRect.top),
+                        (int) Math.ceil(boundingRect.right),
+                        (int) Math.ceil(boundingRect.bottom));
             }
 
             do {
@@ -5154,10 +5154,10 @@
                         RectF boundingRect = attachInfo.mTmpTransformRect;
                         boundingRect.set(dirty);
                         m.mapRect(boundingRect);
-                        dirty.set((int) (boundingRect.left - 0.5f),
-                                (int) (boundingRect.top - 0.5f),
-                                (int) (boundingRect.right + 0.5f),
-                                (int) (boundingRect.bottom + 0.5f));
+                        dirty.set((int) Math.floor(boundingRect.left),
+                                (int) Math.floor(boundingRect.top),
+                                (int) Math.ceil(boundingRect.right),
+                                (int) Math.ceil(boundingRect.bottom));
                     }
                 }
             } while (parent != null);
@@ -5457,8 +5457,8 @@
                 position[0] = offset.x;
                 position[1] = offset.y;
                 child.getMatrix().mapPoints(position);
-                offset.x = (int) (position[0] + 0.5f);
-                offset.y = (int) (position[1] + 0.5f);
+                offset.x = Math.round(position[0]);
+                offset.y = Math.round(position[1]);
             }
             offset.x += dx;
             offset.y += dy;
@@ -5485,8 +5485,8 @@
             rectIsVisible = rect.intersect(mClipBounds.left, mClipBounds.top, mClipBounds.right,
                     mClipBounds.bottom);
         }
-        r.set((int) (rect.left + 0.5f), (int) (rect.top + 0.5f), (int) (rect.right + 0.5f),
-                (int) (rect.bottom + 0.5f));
+        r.set((int) Math.floor(rect.left), (int) Math.floor(rect.top),
+                (int) Math.ceil(rect.right), (int) Math.ceil(rect.bottom));
         if (rectIsVisible && mParent != null) {
             rectIsVisible = mParent.getChildVisibleRect(this, r, offset);
         }
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 2c5e50c..08c7935 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -30,6 +30,9 @@
     public static final int QS_LOCK_TILE = 257;
     public static final int QS_USER_TILE = 258;
     public static final int QS_BATTERY_TILE = 259;
+    public static final int NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 260;
+    public static final int ACTION_ZEN_ALLOW_PEEK = 261;
+    public static final int ACTION_ZEN_ALLOW_LIGHTS = 262;
 
     public static void visible(Context context, int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/policy/BackdropFrameRenderer.java b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
new file mode 100644
index 0000000..b101733
--- /dev/null
+++ b/core/java/com/android/internal/policy/BackdropFrameRenderer.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.internal.policy;
+
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Looper;
+import android.view.Choreographer;
+import android.view.DisplayListCanvas;
+import android.view.RenderNode;
+import android.view.ThreadedRenderer;
+import android.view.View;
+
+/**
+ * The thread which draws a fill in background while the app is resizing in areas where the app
+ * content draw is lagging behind the resize operation.
+ * It starts with the creation and it ends once someone calls destroy().
+ * Any size changes can be passed by a call to setTargetRect will passed to the thread and
+ * executed via the Choreographer.
+ * @hide
+ */
+public class BackdropFrameRenderer extends Thread implements Choreographer.FrameCallback {
+
+    private DecorView mDecorView;
+
+    // This is containing the last requested size by a resize command. Note that this size might
+    // or might not have been applied to the output already.
+    private final Rect mTargetRect = new Rect();
+
+    // The render nodes for the multi threaded renderer.
+    private ThreadedRenderer mRenderer;
+    private RenderNode mFrameAndBackdropNode;
+
+    private final Rect mOldTargetRect = new Rect();
+    private final Rect mNewTargetRect = new Rect();
+    private Choreographer mChoreographer;
+
+    // Cached size values from the last render for the case that the view hierarchy is gone
+    // during a configuration change.
+    private int mLastContentWidth;
+    private int mLastContentHeight;
+    private int mLastCaptionHeight;
+    private int mLastXOffset;
+    private int mLastYOffset;
+
+    // Whether to report when next frame is drawn or not.
+    private boolean mReportNextDraw;
+
+    private Drawable mCaptionBackgroundDrawable;
+    private Drawable mResizingBackgroundDrawable;
+
+    public BackdropFrameRenderer(DecorView decorView, ThreadedRenderer renderer, Rect initialBounds,
+            Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawable) {
+        setName("ResizeFrame");
+
+        mRenderer = renderer;
+        onResourcesLoaded(decorView, resizingBackgroundDrawable, captionBackgroundDrawable);
+
+        // Create a render node for the content and frame backdrop
+        // which can be resized independently from the content.
+        mFrameAndBackdropNode = RenderNode.create("FrameAndBackdropNode", null);
+
+        mRenderer.addRenderNode(mFrameAndBackdropNode, true);
+
+        // Set the initial bounds and draw once so that we do not get a broken frame.
+        mTargetRect.set(initialBounds);
+        synchronized (this) {
+            changeWindowSizeLocked(initialBounds);
+        }
+
+        // Kick off our draw thread.
+        start();
+    }
+
+    void onResourcesLoaded(DecorView decorView, Drawable resizingBackgroundDrawable,
+            Drawable captionBackgroundDrawableDrawable) {
+        mDecorView = decorView;
+        mResizingBackgroundDrawable = resizingBackgroundDrawable;
+        mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable;
+    }
+
+    /**
+     * Call this function asynchronously when the window size has been changed. The change will
+     * be picked up once per frame and the frame will be re-rendered accordingly.
+     * @param newTargetBounds The new target bounds.
+     */
+    public void setTargetRect(Rect newTargetBounds) {
+        synchronized (this) {
+            mTargetRect.set(newTargetBounds);
+            // Notify of a bounds change.
+            pingRenderLocked();
+        }
+    }
+
+    /**
+     * The window got replaced due to a configuration change.
+     */
+    public void onConfigurationChange() {
+        synchronized (this) {
+            if (mRenderer != null) {
+                // Enforce a window redraw.
+                mOldTargetRect.set(0, 0, 0, 0);
+                pingRenderLocked();
+            }
+        }
+    }
+
+    /**
+     * All resources of the renderer will be released. This function can be called from the
+     * the UI thread as well as the renderer thread.
+     */
+    public void releaseRenderer() {
+        synchronized (this) {
+            if (mRenderer != null) {
+                // Invalidate the current content bounds.
+                mRenderer.setContentDrawBounds(0, 0, 0, 0);
+
+                // Remove the render node again
+                // (see comment above - better to do that only once).
+                mRenderer.removeRenderNode(mFrameAndBackdropNode);
+
+                mRenderer = null;
+
+                // Exit the renderer loop.
+                pingRenderLocked();
+            }
+        }
+    }
+
+    @Override
+    public void run() {
+        try {
+            Looper.prepare();
+            synchronized (this) {
+                mChoreographer = Choreographer.getInstance();
+
+                // Draw at least once.
+                mChoreographer.postFrameCallback(this);
+            }
+            Looper.loop();
+        } finally {
+            releaseRenderer();
+        }
+        synchronized (this) {
+            // Make sure no more messages are being sent.
+            mChoreographer = null;
+        }
+    }
+
+    /**
+     * The implementation of the FrameCallback.
+     * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
+     * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
+     */
+    @Override
+    public void doFrame(long frameTimeNanos) {
+        synchronized (this) {
+            if (mRenderer == null) {
+                reportDrawIfNeeded();
+                // Tell the looper to stop. We are done.
+                Looper.myLooper().quit();
+                return;
+            }
+            mNewTargetRect.set(mTargetRect);
+            if (!mNewTargetRect.equals(mOldTargetRect) || mReportNextDraw) {
+                mOldTargetRect.set(mNewTargetRect);
+                changeWindowSizeLocked(mNewTargetRect);
+            }
+        }
+    }
+
+    /**
+     * The content is about to be drawn and we got the location of where it will be shown.
+     * If a "changeWindowSizeLocked" call has already been processed, we will re-issue the call
+     * if the previous call was ignored since the size was unknown.
+     * @param xOffset The x offset where the content is drawn to.
+     * @param yOffset The y offset where the content is drawn to.
+     * @param xSize The width size of the content. This should not be 0.
+     * @param ySize The height of the content.
+     * @return true if a frame should be requested after the content is drawn; false otherwise.
+     */
+    public boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) {
+        synchronized (this) {
+            final boolean firstCall = mLastContentWidth == 0;
+            // The current content buffer is drawn here.
+            mLastContentWidth = xSize;
+            mLastContentHeight = ySize - mLastCaptionHeight;
+            mLastXOffset = xOffset;
+            mLastYOffset = yOffset;
+
+            mRenderer.setContentDrawBounds(
+                    mLastXOffset,
+                    mLastYOffset,
+                    mLastXOffset + mLastContentWidth,
+                    mLastYOffset + mLastCaptionHeight + mLastContentHeight);
+            // If this was the first call and changeWindowSizeLocked got already called prior
+            // to us, we should re-issue a changeWindowSizeLocked now.
+            return firstCall
+                    && (mLastCaptionHeight != 0 || !mDecorView.isShowingCaption());
+        }
+    }
+
+    public void onRequestDraw(boolean reportNextDraw) {
+        synchronized (this) {
+            mReportNextDraw = reportNextDraw;
+            mOldTargetRect.set(0, 0, 0, 0);
+            pingRenderLocked();
+        }
+    }
+
+    /**
+     * Resizing the frame to fit the new window size.
+     * @param newBounds The window bounds which needs to be drawn.
+     */
+    private void changeWindowSizeLocked(Rect newBounds) {
+
+        // While a configuration change is taking place the view hierarchy might become
+        // inaccessible. For that case we remember the previous metrics to avoid flashes.
+        // Note that even when there is no visible caption, the caption child will exist.
+        final int captionHeight = mDecorView.getCaptionHeight();
+        // The caption height will probably never dynamically change while we are resizing.
+        // Once set to something other then 0 it should be kept that way.
+        if (captionHeight != 0) {
+            // Remember the height of the caption.
+            mLastCaptionHeight = captionHeight;
+        }
+
+        // Make sure that the other thread has already prepared the render draw calls for the
+        // content. If any size is 0, we have to wait for it to be drawn first.
+        if ((mLastCaptionHeight == 0 && mDecorView.isShowingCaption()) ||
+                mLastContentWidth == 0 || mLastContentHeight == 0) {
+            return;
+        }
+
+        // Since the surface is spanning the entire screen, we have to add the start offset of
+        // the bounds to get to the surface location.
+        final int left = mLastXOffset + newBounds.left;
+        final int top = mLastYOffset + newBounds.top;
+        final int width = newBounds.width();
+        final int height = newBounds.height();
+
+        mFrameAndBackdropNode.setLeftTopRightBottom(left, top, left + width, top + height);
+
+        // Draw the caption and content backdrops in to our render node.
+        final DisplayListCanvas canvas = mFrameAndBackdropNode.start(width, height);
+        mCaptionBackgroundDrawable.setBounds(0, 0, left + width, top + mLastCaptionHeight);
+        mCaptionBackgroundDrawable.draw(canvas);
+
+        // The backdrop: clear everything with the background. Clipping is done elsewhere.
+        mResizingBackgroundDrawable.setBounds(0, mLastCaptionHeight, left + width, top + height);
+        mResizingBackgroundDrawable.draw(canvas);
+        mFrameAndBackdropNode.end(canvas);
+
+        // We need to render the node explicitly
+        mRenderer.drawRenderNode(mFrameAndBackdropNode);
+
+        reportDrawIfNeeded();
+    }
+
+    /** Notify view root that a frame has been drawn by us, if it has requested so. */
+    private void reportDrawIfNeeded() {
+        if (mReportNextDraw) {
+            if (mDecorView.isAttachedToWindow()) {
+                mDecorView.getViewRootImpl().reportDrawFinish();
+            }
+            mReportNextDraw = false;
+        }
+    }
+
+    /**
+     * Sends a message to the renderer to wake up and perform the next action which can be
+     * either the next rendering or the self destruction if mRenderer is null.
+     * Note: This call must be synchronized.
+     */
+    private void pingRenderLocked() {
+        if (mChoreographer != null) {
+            mChoreographer.postFrameCallback(this);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 4f38ff3..077cebc 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -26,6 +26,7 @@
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.BackgroundFallback;
 import com.android.internal.widget.FloatingToolbar;
+import com.android.internal.widget.NonClientDecorView;
 
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
@@ -38,6 +39,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.Build;
+import android.os.RemoteException;
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.TypedValue;
@@ -46,14 +48,17 @@
 import android.view.Gravity;
 import android.view.InputQueue;
 import android.view.KeyEvent;
+import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.ThreadedRenderer;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewStub;
 import android.view.ViewTreeObserver;
 import android.view.Window;
+import android.view.WindowCallbacks;
 import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
@@ -63,6 +68,8 @@
 import android.widget.FrameLayout;
 import android.widget.PopupWindow;
 
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.view.View.MeasureSpec.AT_MOST;
 import static android.view.View.MeasureSpec.EXACTLY;
 import static android.view.View.MeasureSpec.getMode;
@@ -72,8 +79,11 @@
 import static android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN;
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION;
 import static android.view.WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
-class DecorView extends FrameLayout implements RootViewSurfaceTaker {
+/** @hide */
+public class DecorView extends FrameLayout implements RootViewSurfaceTaker, WindowCallbacks {
     private static final String TAG = "DecorView";
 
     private static final boolean SWEEP_OPEN_MENU = false;
@@ -151,6 +161,21 @@
     private Rect mTempRect;
     private Rect mOutsets = new Rect();
 
+    // This is the non client decor view for the window, containing the caption and window control
+    // buttons. The visibility of this decor depends on the workspace and the window type.
+    // If the window type does not require such a view, this member might be null.
+    NonClientDecorView mNonClientDecorView;
+
+    // The non client decor needs to adapt to the used workspace. Since querying and changing the
+    // workspace is expensive, this is the workspace value the window is currently set up for.
+    int mWorkspaceId;
+
+    private boolean mWindowResizeCallbacksAdded = false;
+
+    public BackdropFrameRenderer mBackdropFrameRenderer = null;
+    private Drawable mResizingBackgroundDrawable;
+    private Drawable mCaptionBackgroundDrawable;
+
     DecorView(Context context, int featureId, PhoneWindow window) {
         super(context);
         mFeatureId = featureId;
@@ -326,7 +351,7 @@
     @Override
     public boolean onInterceptTouchEvent(MotionEvent event) {
         int action = event.getAction();
-        if (mHasNonClientDecor && mWindow.mNonClientDecorView.mVisible) {
+        if (mHasNonClientDecor && mNonClientDecorView.mVisible) {
             // Don't dispatch ACTION_DOWN to the non client decor if the window is
             // resizable and the event was (starting) outside the window.
             // Window resizing events should be handled by WindowManager.
@@ -1209,6 +1234,17 @@
              */
             mWindow.openPanelsAfterRestore();
         }
+
+        if (!mWindowResizeCallbacksAdded) {
+            // If there is no window callback installed there was no window set before. Set it now.
+            // Note that our ViewRootImpl object will not change.
+            getViewRootImpl().addWindowCallbacks(this);
+            mWindowResizeCallbacksAdded = true;
+        } else if (mBackdropFrameRenderer != null) {
+            // We are resizing and this call happened due to a configuration change. Tell the
+            // renderer about it.
+            mBackdropFrameRenderer.onConfigurationChange();
+        }
     }
 
     @Override
@@ -1240,6 +1276,11 @@
         if (st != null && st.menu != null && mFeatureId < 0) {
             st.menu.close();
         }
+
+        if (mWindowResizeCallbacksAdded) {
+            getViewRootImpl().removeWindowCallbacks(this);
+            mWindowResizeCallbacksAdded = false;
+        }
     }
 
     @Override
@@ -1483,19 +1524,245 @@
      * @return Returns true when the window has a shadow created by the non client decor.
      **/
     private boolean windowHasShadow() {
-        return windowHasNonClientDecor() && ActivityManager.StackId
-                .hasWindowShadow(mWindow.mWorkspaceId);
+        return windowHasNonClientDecor() && ActivityManager.StackId.hasWindowShadow(mWorkspaceId);
     }
 
     void setWindow(PhoneWindow phoneWindow) {
         mWindow = phoneWindow;
         Context context = getContext();
         if (context instanceof DecorContext) {
-            DecorContext decorContex = (DecorContext) context;
-            decorContex.setPhoneWindow(mWindow);
+            DecorContext decorContext = (DecorContext) context;
+            decorContext.setPhoneWindow(mWindow);
         }
     }
 
+    void onConfigurationChanged() {
+        if (mNonClientDecorView != null) {
+            int workspaceId = getWorkspaceId();
+            if (mWorkspaceId != workspaceId) {
+                mWorkspaceId = workspaceId;
+                // We might have to change the kind of surface before we do anything else.
+                mNonClientDecorView.onConfigurationChanged(
+                        ActivityManager.StackId.hasWindowDecor(mWorkspaceId),
+                        ActivityManager.StackId.hasWindowShadow(mWorkspaceId));
+                enableNonClientDecor(ActivityManager.StackId.hasWindowDecor(workspaceId));
+            }
+        }
+    }
+
+    View onResourcesLoaded(LayoutInflater inflater, int layoutResource) {
+        mWorkspaceId = getWorkspaceId();
+
+        mResizingBackgroundDrawable = getResizingBackgroundDrawable(
+                mWindow.mBackgroundResource, mWindow.mBackgroundFallbackResource);
+        mCaptionBackgroundDrawable =
+                getContext().getDrawable(R.drawable.non_client_decor_title_focused);
+
+        if (mBackdropFrameRenderer != null) {
+            mBackdropFrameRenderer.onResourcesLoaded(
+                    this, mResizingBackgroundDrawable, mCaptionBackgroundDrawable);
+        }
+
+        mNonClientDecorView = createNonClientDecorView(inflater);
+        final View root = inflater.inflate(layoutResource, null);
+        if (mNonClientDecorView != null) {
+            if (mNonClientDecorView.getParent() == null) {
+                addView(mNonClientDecorView,
+                        new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+            }
+            mNonClientDecorView.addView(root,
+                    new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        } else {
+            addView(root, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+        }
+        mContentRoot = (ViewGroup) root;
+        return root;
+    }
+
+    // Free floating overlapping windows require a non client decor with a caption and shadow..
+    private NonClientDecorView createNonClientDecorView(LayoutInflater inflater) {
+        NonClientDecorView nonClientDecorView = null;
+        for (int i = getChildCount() - 1; i >= 0 && nonClientDecorView == null; i--) {
+            View view = getChildAt(i);
+            if (view instanceof NonClientDecorView) {
+                // The decor was most likely saved from a relaunch - so reuse it.
+                nonClientDecorView = (NonClientDecorView) view;
+                removeViewAt(i);
+            }
+        }
+        final WindowManager.LayoutParams attrs = mWindow.getAttributes();
+        boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||
+                attrs.type == TYPE_APPLICATION;
+        // Only a non floating application window on one of the allowed workspaces can get a non
+        // client decor.
+        final boolean hasNonClientDecor = ActivityManager.StackId.hasWindowDecor(mWorkspaceId);
+        if (!mWindow.isFloating() && isApplication && hasNonClientDecor) {
+            // Dependent on the brightness of the used title we either use the
+            // dark or the light button frame.
+            if (nonClientDecorView == null) {
+                Context context = getContext();
+                TypedValue value = new TypedValue();
+                context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
+                inflater = inflater.from(context);
+                if (Color.luminance(value.data) < 0.5) {
+                    nonClientDecorView = (NonClientDecorView) inflater.inflate(
+                            R.layout.non_client_decor_dark, null);
+                } else {
+                    nonClientDecorView = (NonClientDecorView) inflater.inflate(
+                            R.layout.non_client_decor_light, null);
+                }
+            }
+            nonClientDecorView.setPhoneWindow(mWindow,
+                    ActivityManager.StackId.hasWindowDecor(mWorkspaceId),
+                    ActivityManager.StackId.hasWindowShadow(mWorkspaceId));
+        } else {
+            nonClientDecorView = null;
+        }
+
+        // Tell the decor if it has a visible non client decor.
+        enableNonClientDecor(nonClientDecorView != null && hasNonClientDecor);
+        return nonClientDecorView;
+    }
+
+    /**
+     * Returns the color used to fill areas the app has not rendered content to yet when the
+     * user is resizing the window of an activity in multi-window mode.
+     */
+    private Drawable getResizingBackgroundDrawable(int backgroundRes, int backgroundFallbackRes) {
+        final Context context = getContext();
+
+        if (backgroundRes != 0) {
+            final Drawable drawable = context.getDrawable(backgroundRes);
+            if (drawable != null) {
+                return drawable;
+            }
+        }
+
+        if (backgroundFallbackRes != 0) {
+            final Drawable fallbackDrawable = context.getDrawable(backgroundFallbackRes);
+            if (fallbackDrawable != null) {
+                return fallbackDrawable;
+            }
+        }
+
+        // We shouldn't really get here as the background fallback should be always available since
+        // it is defaulted by the system.
+        Log.w(TAG, "Failed to find background drawable for PhoneWindow=" + mWindow);
+        return null;
+    }
+
+    /**
+     * Returns the Id of the workspace which contains this window.
+     * Note that if no workspace can be determined - which usually means that it was not
+     * created for an activity - the fullscreen workspace ID will be returned.
+     * @return Returns the workspace stack id which contains this window.
+     **/
+    private int getWorkspaceId() {
+        int workspaceId = INVALID_STACK_ID;
+        final Window.WindowControllerCallback callback = mWindow.getWindowControllerCallback();
+        if (callback != null) {
+            try {
+                workspaceId = callback.getWindowStackId();
+            } catch (RemoteException ex) {
+                Log.e(TAG, "Failed to get the workspace ID of a PhoneWindow.");
+            }
+        }
+        if (workspaceId == INVALID_STACK_ID) {
+            return FULLSCREEN_WORKSPACE_STACK_ID;
+        }
+        return workspaceId;
+    }
+
+    void clearContentView() {
+        if (mNonClientDecorView != null) {
+            if (mNonClientDecorView.getChildCount() > 1) {
+                mNonClientDecorView.removeViewAt(1);
+            }
+        } else {
+            // This window doesn't have non client decor, so we need to just remove the
+            // children of the decor view.
+            removeAllViews();
+        }
+    }
+
+    @Override
+    public void onWindowSizeIsChanging(Rect newBounds) {
+        if (mBackdropFrameRenderer != null) {
+            mBackdropFrameRenderer.setTargetRect(newBounds);
+        }
+    }
+
+    @Override
+    public void onWindowDragResizeStart(Rect initialBounds) {
+        if (mWindow.isDestroyed()) {
+            // If the owner's window is gone, we should not be able to come here anymore.
+            releaseThreadedRenderer();
+            return;
+        }
+        if (mBackdropFrameRenderer != null) {
+            return;
+        }
+        final ThreadedRenderer renderer = (ThreadedRenderer) getHardwareRenderer();
+        if (renderer != null) {
+            mBackdropFrameRenderer = new BackdropFrameRenderer(this, renderer,
+                    initialBounds, mResizingBackgroundDrawable, mCaptionBackgroundDrawable);
+
+            // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
+            // If we want to get the shadow shown while resizing, we would need to elevate a new
+            // element which owns the caption and has the elevation.
+            updateElevation();
+        }
+    }
+
+    @Override
+    public void onWindowDragResizeEnd() {
+        releaseThreadedRenderer();
+    }
+
+    @Override
+    public boolean onContentDrawn(int offsetX, int offsetY, int sizeX, int sizeY) {
+        if (mBackdropFrameRenderer == null) {
+            return false;
+        }
+        return mBackdropFrameRenderer.onContentDrawn(offsetX, offsetY, sizeX, sizeY);
+    }
+
+    @Override
+    public void onRequestDraw(boolean reportNextDraw) {
+        if (mBackdropFrameRenderer != null) {
+            mBackdropFrameRenderer.onRequestDraw(reportNextDraw);
+        } else if (reportNextDraw) {
+            // If render thread is gone, just report immediately.
+            if (isAttachedToWindow()) {
+                getViewRootImpl().reportDrawFinish();
+            }
+        }
+    }
+
+    /** Release the renderer thread which is usually done when the user stops resizing. */
+    private void releaseThreadedRenderer() {
+        if (mBackdropFrameRenderer != null) {
+            mBackdropFrameRenderer.releaseRenderer();
+            mBackdropFrameRenderer = null;
+            // Bring the shadow back.
+            updateElevation();
+        }
+    }
+
+    private void updateElevation() {
+        if (mNonClientDecorView != null) {
+            mNonClientDecorView.updateElevation();
+        }
+    }
+
+    boolean isShowingCaption() {
+        return mNonClientDecorView != null && mNonClientDecorView.isShowingDecor();
+    }
+
+    int getCaptionHeight() {
+        return isShowingCaption() ? mNonClientDecorView.getDecorCaptionHeight() : 0;
+    }
+
     private static class ColorViewState {
         View view = null;
         int targetVisibility = View.INVISIBLE;
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index c427149..6e7e5cf 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -16,13 +16,10 @@
 
 package com.android.internal.policy;
 
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.*;
 
-import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerNative;
 import android.app.SearchManager;
 import android.os.UserHandle;
@@ -60,7 +57,6 @@
 import com.android.internal.view.menu.MenuPresenter;
 import com.android.internal.view.menu.MenuView;
 import com.android.internal.widget.DecorContentParent;
-import com.android.internal.widget.NonClientDecorView;
 import com.android.internal.widget.SwipeDismissLayout;
 
 import android.app.ActivityManager;
@@ -72,7 +68,6 @@
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Color;
-import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.media.session.MediaController;
@@ -149,15 +144,6 @@
     // view is requested, so we need to force the recreating without introducing an infinite loop.
     private boolean mForceDecorInstall = false;
 
-    // This is the non client decor view for the window, containing the caption and window control
-    // buttons. The visibility of this decor depends on the workspace and the window type.
-    // If the window type does not require such a view, this member might be null.
-    NonClientDecorView mNonClientDecorView;
-
-    // The non client decor needs to adapt to the used workspace. Since querying and changing the
-    // workspace is expensive, this is the workspace value the window is currently set up for.
-    int mWorkspaceId;
-
     // This is the view in which the window contents are placed. It is either
     // mDecor itself, or a child of mDecor where the contents go.
     ViewGroup mContentParent;
@@ -220,12 +206,12 @@
 
     private ProgressBar mHorizontalProgressBar;
 
-    private int mBackgroundResource = 0;
-    private int mBackgroundFallbackResource = 0;
+    int mBackgroundResource = 0;
+    int mBackgroundFallbackResource = 0;
 
     private Drawable mBackgroundDrawable;
 
-    private boolean mLoadEleveation = true;
+    private boolean mLoadElevation = true;
     private float mElevation;
 
     /** Whether window content should be clipped to the background outline. */
@@ -305,7 +291,7 @@
         if (preservedWindow != null) {
             mDecor = (DecorView) preservedWindow.getDecorView();
             mElevation = preservedWindow.getElevation();
-            mLoadEleveation = false;
+            mLoadElevation = false;
             mForceDecorInstall = true;
             // If we're preserving window, carry over the app token from the preserved
             // window, as we'll be skipping the addView in handleResumeActivity(), and
@@ -478,15 +464,10 @@
         }
     }
 
+    @Override
     public void clearContentView() {
-        if (mNonClientDecorView != null) {
-            if (mNonClientDecorView.getChildCount() > 1) {
-                mNonClientDecorView.removeViewAt(1);
-            }
-        } else {
-            // This window doesn't have non client decor, so we need to just remove the children
-            // of the decor view.
-            mDecor.removeAllViews();
+        if (mDecor != null) {
+            mDecor.clearContentView();
         }
     }
 
@@ -700,15 +681,8 @@
                 }
             }
         }
-        if (mNonClientDecorView != null) {
-            int workspaceId = getWorkspaceId();
-            if (mWorkspaceId != workspaceId) {
-                mWorkspaceId = workspaceId;
-                // We might have to change the kind of surface before we do anything else.
-                mNonClientDecorView.phoneWindowUpdated(StackId.hasWindowDecor(mWorkspaceId),
-                        StackId.hasWindowShadow(mWorkspaceId));
-                mDecor.enableNonClientDecor(StackId.hasWindowDecor(workspaceId));
-            }
+        if (mDecor != null) {
+            mDecor.onConfigurationChanged();
         }
     }
 
@@ -2511,7 +2485,7 @@
                             + Integer.toHexString(mFrameResource));
                 }
             }
-            if (mLoadEleveation) {
+            if (mLoadElevation) {
                 mElevation = a.getDimension(R.styleable.Window_windowElevation, 0);
             }
             mClipToOutline = a.getBoolean(R.styleable.Window_windowClipToOutline, false);
@@ -2581,19 +2555,7 @@
         }
 
         mDecor.startChanging();
-
-        mNonClientDecorView = createNonClientDecorView();
-        View in = mLayoutInflater.inflate(layoutResource, null);
-        if (mNonClientDecorView != null) {
-            if (mNonClientDecorView.getParent() == null) {
-                decor.addView(mNonClientDecorView,
-                        new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-            }
-            mNonClientDecorView.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-        } else {
-            decor.addView(in, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-        }
-        decor.mContentRoot = (ViewGroup) in;
+        final View in = mDecor.onResourcesLoaded(mLayoutInflater, layoutResource);
 
         ViewGroup contentParent = (ViewGroup)findViewById(ID_ANDROID_CONTENT);
         if (contentParent == null) {
@@ -2648,50 +2610,6 @@
         return contentParent;
     }
 
-    // Free floating overlapping windows require a non client decor with a caption and shadow..
-    private NonClientDecorView createNonClientDecorView() {
-        NonClientDecorView nonClientDecorView = null;
-        for (int i = mDecor.getChildCount() - 1; i >= 0 && nonClientDecorView == null; i--) {
-            View view = mDecor.getChildAt(i);
-            if (view instanceof NonClientDecorView) {
-                // The decor was most likely saved from a relaunch - so reuse it.
-                nonClientDecorView = (NonClientDecorView) view;
-                mDecor.removeViewAt(i);
-            }
-        }
-        final WindowManager.LayoutParams attrs = getAttributes();
-        boolean isApplication = attrs.type == TYPE_BASE_APPLICATION ||
-                attrs.type == TYPE_APPLICATION;
-        mWorkspaceId = getWorkspaceId();
-        // Only a non floating application window on one of the allowed workspaces can get a non
-        // client decor.
-        if (!isFloating() && isApplication && StackId.isStaticStack(mWorkspaceId)) {
-            // Dependent on the brightness of the used title we either use the
-            // dark or the light button frame.
-            if (nonClientDecorView == null) {
-                Context context = mDecor.getContext();
-                TypedValue value = new TypedValue();
-                context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
-                LayoutInflater inflater = mLayoutInflater.from(context);
-                if (Color.luminance(value.data) < 0.5) {
-                    nonClientDecorView = (NonClientDecorView) inflater.inflate(
-                            R.layout.non_client_decor_dark, null);
-                } else {
-                    nonClientDecorView = (NonClientDecorView) inflater.inflate(
-                            R.layout.non_client_decor_light, null);
-                }
-            }
-            nonClientDecorView.setPhoneWindow(this, StackId.hasWindowDecor(mWorkspaceId),
-                    StackId.hasWindowShadow(mWorkspaceId), getResizingBackgroundDrawable(),
-                    mDecor.getContext().getDrawable(R.drawable.non_client_decor_title_focused));
-        }
-        // Tell the decor if it has a visible non client decor.
-        mDecor.enableNonClientDecor(
-                nonClientDecorView != null&& StackId.hasWindowDecor(mWorkspaceId));
-
-        return nonClientDecorView;
-    }
-
     /** @hide */
     public void alwaysReadCloseOnTouchAttr() {
         mAlwaysReadCloseOnTouchAttr = true;
@@ -3819,28 +3737,6 @@
         mIsStartingWindow = isStartingWindow;
     }
 
-    /**
-     * Returns the Id of the workspace which contains this window.
-     * Note that if no workspace can be determined - which usually means that it was not
-     * created for an activity - the fullscreen workspace ID will be returned.
-     * @return Returns the workspace stack id which contains this window.
-     **/
-    private int getWorkspaceId() {
-        int workspaceId = INVALID_STACK_ID;
-        WindowControllerCallback callback = getWindowControllerCallback();
-        if (callback != null) {
-            try {
-                workspaceId = callback.getWindowStackId();
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Failed to get the workspace ID of a PhoneWindow.");
-            }
-        }
-        if (workspaceId == INVALID_STACK_ID) {
-            return FULLSCREEN_WORKSPACE_STACK_ID;
-        }
-        return workspaceId;
-    }
-
     @Override
     public void setTheme(int resid) {
         mTheme = resid;
@@ -3851,31 +3747,4 @@
             }
         }
     }
-
-    /**
-     * Returns the color used to fill areas the app has not rendered content to yet when the user
-     * is resizing the window of an activity in multi-window mode.
-     * */
-    private Drawable getResizingBackgroundDrawable() {
-        final Context context = mDecor.getContext();
-
-        if (mBackgroundResource != 0) {
-            final Drawable drawable = context.getDrawable(mBackgroundResource);
-            if (drawable != null) {
-                return drawable;
-            }
-        }
-
-        if (mBackgroundFallbackResource != 0) {
-            final Drawable fallbackDrawable = context.getDrawable(mBackgroundFallbackResource);
-            if (fallbackDrawable != null) {
-                return fallbackDrawable;
-            }
-        }
-
-        // We shouldn't really get here as the background fallback should be always available since
-        // it is defaulted by the system.
-        Log.w(TAG, "Failed to find background drawable for PhoneWindow=" + this);
-        return null;
-    }
 }
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index de6e228..33b8e05 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -19,26 +19,19 @@
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 
 import android.content.Context;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.os.Looper;
 import android.os.RemoteException;
 import android.util.AttributeSet;
-import android.view.Choreographer;
-import android.view.DisplayListCanvas;
 import android.view.MotionEvent;
-import android.view.RenderNode;
-import android.view.ThreadedRenderer;
 import android.view.View;
 import android.widget.LinearLayout;
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 import android.view.Window;
-import android.view.WindowCallbacks;
 import android.util.Log;
 import android.util.TypedValue;
 
 import com.android.internal.R;
+import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneWindow;
 
 /**
@@ -67,7 +60,7 @@
  * This will be mitigated once b/22527834 will be addressed.
  */
 public class NonClientDecorView extends LinearLayout
-        implements View.OnClickListener, View.OnTouchListener, WindowCallbacks {
+        implements View.OnClickListener, View.OnTouchListener {
     private final static String TAG = "NonClientDecorView";
     // The height of a window which has focus in DIP.
     private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20;
@@ -76,8 +69,6 @@
     private PhoneWindow mOwner = null;
     private boolean mWindowHasShadow = false;
     private boolean mShowDecor = false;
-    // True when this object is listening for window size changes.
-    private boolean mAttachedCallbacksToRootViewImpl = false;
 
     // True if the window is being dragged.
     private boolean mDragging = false;
@@ -96,12 +87,6 @@
     // to max until the first layout command has been executed.
     private boolean mAllowUpdateElevation = false;
 
-    // The resize frame renderer.
-    private ResizeFrameThread mFrameRendererThread = null;
-
-    private Drawable mResizingBackgroundDrawable;
-    private Drawable mCaptionBackgroundDrawable;
-
     public NonClientDecorView(Context context) {
         super(context);
     }
@@ -114,37 +99,10 @@
         super(context, attrs, defStyle);
     }
 
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (!mAttachedCallbacksToRootViewImpl) {
-            // If there is no window callback installed there was no window set before. Set it now.
-            // Note that our ViewRootImpl object will not change.
-            getViewRootImpl().addWindowCallbacks(this);
-            mAttachedCallbacksToRootViewImpl = true;
-        } else if (mFrameRendererThread != null) {
-            // We are resizing and this call happened due to a configuration change. Tell the
-            // renderer about it.
-            mFrameRendererThread.onConfigurationChange();
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mAttachedCallbacksToRootViewImpl) {
-            getViewRootImpl().removeWindowCallbacks(this);
-            mAttachedCallbacksToRootViewImpl = false;
-        }
-    }
-
-    public void setPhoneWindow(PhoneWindow owner, boolean showDecor, boolean windowHasShadow,
-            Drawable resizingBackgroundDrawable, Drawable captionBackgroundDrawableDrawable) {
+    public void setPhoneWindow(PhoneWindow owner, boolean showDecor, boolean windowHasShadow) {
         mOwner = owner;
         mWindowHasShadow = windowHasShadow;
         mShowDecor = showDecor;
-        mResizingBackgroundDrawable = resizingBackgroundDrawable;
-        mCaptionBackgroundDrawable = captionBackgroundDrawableDrawable;
         updateCaptionVisibility();
         if (mWindowHasShadow) {
             initializeElevation();
@@ -208,7 +166,7 @@
      * @param showDecor True if the decor should be shown.
      * @param windowHasShadow True when the window should show a shadow.
      **/
-    public void phoneWindowUpdated(boolean showDecor, boolean windowHasShadow) {
+    public void onConfigurationChanged(boolean showDecor, boolean windowHasShadow) {
         mShowDecor = showDecor;
         updateCaptionVisibility();
         if (windowHasShadow != mWindowHasShadow) {
@@ -294,11 +252,12 @@
      * Note: Windows which have (temporarily) changed their attributes to cover the SystemUI
      *       will get no shadow as they are expected to be "full screen".
      **/
-    private void updateElevation() {
+    public void updateElevation() {
         float elevation = 0;
         // Do not use a shadow when we are in resizing mode (mRenderer not null) since the shadow
         // is bound to the content size and not the target size.
-        if (mWindowHasShadow && mFrameRendererThread == null) {
+        if (mWindowHasShadow
+                && ((DecorView) mOwner.getDecorView()).mBackdropFrameRenderer == null) {
             boolean fill = isFillingScreen();
             elevation = fill ? 0 :
                     (mWindowHasFocus ? DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP :
@@ -340,329 +299,12 @@
         }
     }
 
-    @Override
-    public void onWindowDragResizeStart(Rect initialBounds) {
-        if (mOwner.isDestroyed()) {
-            // If the owner's window is gone, we should not be able to come here anymore.
-            releaseResources();
-            return;
-        }
-        if (mFrameRendererThread != null) {
-            return;
-        }
-        final ThreadedRenderer renderer =
-                (ThreadedRenderer) mOwner.getDecorView().getHardwareRenderer();
-        if (renderer != null) {
-            mFrameRendererThread = new ResizeFrameThread(renderer, initialBounds);
-            // Get rid of the shadow while we are resizing. Shadow drawing takes considerable time.
-            // If we want to get the shadow shown while resizing, we would need to elevate a new
-            // element which owns the caption and has the elevation.
-            updateElevation();
-        }
+    public boolean isShowingDecor() {
+        return mShowDecor;
     }
 
-    @Override
-    public boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) {
-        if (mFrameRendererThread == null) {
-            return false;
-        }
-        return mFrameRendererThread.onContentDrawn(xOffset, yOffset, xSize, ySize);
-    }
-
-    @Override
-    public void onRequestDraw(boolean reportNextDraw) {
-        if (mFrameRendererThread != null) {
-            mFrameRendererThread.onRequestDraw(reportNextDraw);
-        } else if (reportNextDraw) {
-            // If render thread is gone, just report immediately.
-            if (isAttachedToWindow()) {
-                getViewRootImpl().reportDrawFinish();
-            }
-        }
-    }
-
-    @Override
-    public void onWindowDragResizeEnd() {
-        releaseThreadedRenderer();
-    }
-
-    @Override
-    public void onWindowSizeIsChanging(Rect newBounds) {
-        if (mFrameRendererThread != null) {
-            mFrameRendererThread.setTargetRect(newBounds);
-        }
-    }
-
-    /**
-     * Release the renderer thread which is usually done when the user stops resizing.
-     */
-    private void releaseThreadedRenderer() {
-        if (mFrameRendererThread != null) {
-            mFrameRendererThread.releaseRenderer();
-            mFrameRendererThread = null;
-            // Bring the shadow back.
-            updateElevation();
-        }
-    }
-
-    /**
-     * Called when the parent window is destroyed to release all resources. Note that this will also
-     * destroy the renderer thread.
-     */
-    private void releaseResources() {
-        releaseThreadedRenderer();
-    }
-
-    /**
-     * The thread which draws the chrome while we are resizing.
-     * It starts with the creation and it ends once someone calls destroy().
-     * Any size changes can be passed by a call to setTargetRect will passed to the thread and
-     * executed via the Choreographer.
-     * TODO(b/24810450): Separate functionality from non-client-decor so that it can be used
-     * independently.
-     */
-    private class ResizeFrameThread extends Thread implements Choreographer.FrameCallback {
-        // This is containing the last requested size by a resize command. Note that this size might
-        // or might not have been applied to the output already.
-        private final Rect mTargetRect = new Rect();
-
-        // The render nodes for the multi threaded renderer.
-        private ThreadedRenderer mRenderer;
-        private RenderNode mFrameAndBackdropNode;
-
-        private final Rect mOldTargetRect = new Rect();
-        private final Rect mNewTargetRect = new Rect();
-        private Choreographer mChoreographer;
-
-        // Cached size values from the last render for the case that the view hierarchy is gone
-        // during a configuration change.
-        private int mLastContentWidth;
-        private int mLastContentHeight;
-        private int mLastCaptionHeight;
-        private int mLastXOffset;
-        private int mLastYOffset;
-
-        // Whether to report when next frame is drawn or not.
-        private boolean mReportNextDraw;
-
-        ResizeFrameThread(ThreadedRenderer renderer, Rect initialBounds) {
-            setName("ResizeFrame");
-            mRenderer = renderer;
-
-            // Create a render node for the content and frame backdrop
-            // which can be resized independently from the content.
-            mFrameAndBackdropNode = RenderNode.create("FrameAndBackdropNode", null);
-
-            mRenderer.addRenderNode(mFrameAndBackdropNode, true);
-
-            // Set the initial bounds and draw once so that we do not get a broken frame.
-            mTargetRect.set(initialBounds);
-            synchronized (this) {
-                changeWindowSizeLocked(initialBounds);
-            }
-
-            // Kick off our draw thread.
-            start();
-        }
-
-        /**
-         * Call this function asynchronously when the window size has been changed. The change will
-         * be picked up once per frame and the frame will be re-rendered accordingly.
-         * @param newTargetBounds The new target bounds.
-         */
-        public void setTargetRect(Rect newTargetBounds) {
-            synchronized (this) {
-                mTargetRect.set(newTargetBounds);
-                // Notify of a bounds change.
-                pingRenderLocked();
-            }
-        }
-
-        /**
-         * The window got replaced due to a configuration change.
-         */
-        public void onConfigurationChange() {
-            synchronized (this) {
-                if (mRenderer != null) {
-                    // Enforce a window redraw.
-                    mOldTargetRect.set(0, 0, 0, 0);
-                    pingRenderLocked();
-                }
-            }
-        }
-
-        /**
-         * All resources of the renderer will be released. This function can be called from the
-         * the UI thread as well as the renderer thread.
-         */
-        public void releaseRenderer() {
-            synchronized (this) {
-                if (mRenderer != null) {
-                    // Invalidate the current content bounds.
-                    mRenderer.setContentDrawBounds(0, 0, 0, 0);
-
-                    // Remove the render node again
-                    // (see comment above - better to do that only once).
-                    mRenderer.removeRenderNode(mFrameAndBackdropNode);
-
-                    mRenderer = null;
-
-                    // Exit the renderer loop.
-                    pingRenderLocked();
-                }
-            }
-        }
-
-        @Override
-        public void run() {
-            try {
-                Looper.prepare();
-                synchronized (this) {
-                    mChoreographer = Choreographer.getInstance();
-
-                    // Draw at least once.
-                    mChoreographer.postFrameCallback(this);
-                }
-                Looper.loop();
-            } finally {
-                releaseRenderer();
-            }
-            synchronized (this) {
-                // Make sure no more messages are being sent.
-                mChoreographer = null;
-            }
-        }
-
-        /**
-         * The implementation of the FrameCallback.
-         * @param frameTimeNanos The time in nanoseconds when the frame started being rendered,
-         * in the {@link System#nanoTime()} timebase.  Divide this value by {@code 1000000}
-         */
-        @Override
-        public void doFrame(long frameTimeNanos) {
-            synchronized (this) {
-                if (mRenderer == null) {
-                    reportDrawIfNeeded();
-                    // Tell the looper to stop. We are done.
-                    Looper.myLooper().quit();
-                    return;
-                }
-                mNewTargetRect.set(mTargetRect);
-                if (!mNewTargetRect.equals(mOldTargetRect) || mReportNextDraw) {
-                    mOldTargetRect.set(mNewTargetRect);
-                    changeWindowSizeLocked(mNewTargetRect);
-                }
-            }
-        }
-
-        /**
-         * The content is about to be drawn and we got the location of where it will be shown.
-         * If a "changeWindowSizeLocked" call has already been processed, we will re-issue the call
-         * if the previous call was ignored since the size was unknown.
-         * @param xOffset The x offset where the content is drawn to.
-         * @param yOffset The y offset where the content is drawn to.
-         * @param xSize The width size of the content. This should not be 0.
-         * @param ySize The height of the content.
-         * @return true if a frame should be requested after the content is drawn; false otherwise.
-         */
-        public boolean onContentDrawn(int xOffset, int yOffset, int xSize, int ySize) {
-            synchronized (this) {
-                final boolean firstCall = mLastContentWidth == 0;
-                // The current content buffer is drawn here.
-                mLastContentWidth = xSize;
-                mLastContentHeight = ySize - mLastCaptionHeight;
-                mLastXOffset = xOffset;
-                mLastYOffset = yOffset;
-
-                mRenderer.setContentDrawBounds(
-                        mLastXOffset,
-                        mLastYOffset,
-                        mLastXOffset + mLastContentWidth,
-                        mLastYOffset + mLastCaptionHeight + mLastContentHeight);
-                // If this was the first call and changeWindowSizeLocked got already called prior
-                // to us, we should re-issue a changeWindowSizeLocked now.
-                return firstCall && (mLastCaptionHeight != 0 || !mShowDecor);
-            }
-        }
-
-        public void onRequestDraw(boolean reportNextDraw) {
-            synchronized (this) {
-                mReportNextDraw = reportNextDraw;
-                mOldTargetRect.set(0, 0, 0, 0);
-                pingRenderLocked();
-            }
-        }
-
-        /**
-         * Resizing the frame to fit the new window size.
-         * @param newBounds The window bounds which needs to be drawn.
-         */
-        private void changeWindowSizeLocked(Rect newBounds) {
-            // While a configuration change is taking place the view hierarchy might become
-            // inaccessible. For that case we remember the previous metrics to avoid flashes.
-            // Note that even when there is no visible caption, the caption child will exist.
-            View caption = getChildAt(0);
-            if (caption != null) {
-                final int captionHeight = caption.getHeight();
-                // The caption height will probably never dynamically change while we are resizing.
-                // Once set to something other then 0 it should be kept that way.
-                if (captionHeight != 0) {
-                    // Remember the height of the caption.
-                    mLastCaptionHeight = captionHeight;
-                }
-            }
-            // Make sure that the other thread has already prepared the render draw calls for the
-            // content. If any size is 0, we have to wait for it to be drawn first.
-            if ((mLastCaptionHeight == 0 && mShowDecor) ||
-                    mLastContentWidth == 0 || mLastContentHeight == 0) {
-                return;
-            }
-            // Since the surface is spanning the entire screen, we have to add the start offset of
-            // the bounds to get to the surface location.
-            final int left = mLastXOffset + newBounds.left;
-            final int top = mLastYOffset + newBounds.top;
-            final int width = newBounds.width();
-            final int height = newBounds.height();
-
-            mFrameAndBackdropNode.setLeftTopRightBottom(left, top, left + width, top + height);
-
-            // Draw the caption and content backdrops in to our render node.
-            DisplayListCanvas canvas = mFrameAndBackdropNode.start(width, height);
-            mCaptionBackgroundDrawable.setBounds(0, 0, left + width, top + mLastCaptionHeight);
-            mCaptionBackgroundDrawable.draw(canvas);
-
-            // The backdrop: clear everything with the background. Clipping is done elsewhere.
-            mResizingBackgroundDrawable.setBounds(0, mLastCaptionHeight, left + width, top + height);
-            mResizingBackgroundDrawable.draw(canvas);
-            mFrameAndBackdropNode.end(canvas);
-
-            // We need to render the node explicitly
-            mRenderer.drawRenderNode(mFrameAndBackdropNode);
-
-            reportDrawIfNeeded();
-        }
-
-        /**
-         * Notify view root that a frame has been drawn by us, if it has requested so.
-         */
-        private void reportDrawIfNeeded() {
-            if (mReportNextDraw) {
-                if (isAttachedToWindow()) {
-                    getViewRootImpl().reportDrawFinish();
-                }
-                mReportNextDraw = false;
-            }
-        }
-
-        /**
-         * Sends a message to the renderer to wake up and perform the next action which can be
-         * either the next rendering or the self destruction if mRenderer is null.
-         * Note: This call must be synchronized.
-         */
-        private void pingRenderLocked() {
-            if (mChoreographer != null) {
-                mChoreographer.postFrameCallback(this);
-            }
-        }
+    public int getDecorCaptionHeight() {
+        final View caption = getChildAt(0);
+        return (caption != null) ? caption.getHeight() : 0;
     }
 }
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 815d330..65e8058 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -608,15 +608,6 @@
       kEMIntFast,
       kEMJitCompiler,
     } executionMode = kEMDefault;
-    char profilePeriod[sizeof("-Xprofile-period:")-1 + PROPERTY_VALUE_MAX];
-    char profileDuration[sizeof("-Xprofile-duration:")-1 + PROPERTY_VALUE_MAX];
-    char profileInterval[sizeof("-Xprofile-interval:")-1 + PROPERTY_VALUE_MAX];
-    char profileBackoff[sizeof("-Xprofile-backoff:")-1 + PROPERTY_VALUE_MAX];
-    char profileTopKThreshold[sizeof("-Xprofile-top-k-threshold:")-1 + PROPERTY_VALUE_MAX];
-    char profileTopKChangeThreshold[sizeof("-Xprofile-top-k-change-threshold:")-1 +
-                                    PROPERTY_VALUE_MAX];
-    char profileType[sizeof("-Xprofile-type:")-1 + PROPERTY_VALUE_MAX];
-    char profileMaxStackDepth[sizeof("-Xprofile-max-stack-depth:")-1 + PROPERTY_VALUE_MAX];
     char localeOption[sizeof("-Duser.locale=") + PROPERTY_VALUE_MAX];
     char lockProfThresholdBuf[sizeof("-Xlockprofthreshold:")-1 + PROPERTY_VALUE_MAX];
     char nativeBridgeLibrary[sizeof("-XX:NativeBridge=") + PROPERTY_VALUE_MAX];
@@ -835,60 +826,6 @@
         addOption(localeOption);
     }
 
-    /*
-     * Set profiler options
-     */
-    // Whether or not the profiler should be enabled.
-    property_get("dalvik.vm.profiler", propBuf, "0");
-    if (propBuf[0] == '1') {
-        addOption("-Xenable-profiler");
-    }
-
-    // Whether the profile should start upon app startup or be delayed by some random offset
-    // (in seconds) that is bound between 0 and a fixed value.
-    property_get("dalvik.vm.profile.start-immed", propBuf, "0");
-    if (propBuf[0] == '1') {
-        addOption("-Xprofile-start-immediately");
-    }
-
-    // Number of seconds during profile runs.
-    parseRuntimeOption("dalvik.vm.profile.period-secs", profilePeriod, "-Xprofile-period:");
-
-    // Length of each profile run (seconds).
-    parseRuntimeOption("dalvik.vm.profile.duration-secs",
-                       profileDuration,
-                       "-Xprofile-duration:");
-
-    // Polling interval during profile run (microseconds).
-    parseRuntimeOption("dalvik.vm.profile.interval-us", profileInterval, "-Xprofile-interval:");
-
-    // Coefficient for period backoff.  The the period is multiplied
-    // by this value after each profile run.
-    parseRuntimeOption("dalvik.vm.profile.backoff-coeff", profileBackoff, "-Xprofile-backoff:");
-
-    // Top K% of samples that are considered relevant when
-    // deciding if the app should be recompiled.
-    parseRuntimeOption("dalvik.vm.profile.top-k-thr",
-                       profileTopKThreshold,
-                       "-Xprofile-top-k-threshold:");
-
-    // The threshold after which a change in the structure of the
-    // top K% profiled samples becomes significant and triggers
-    // recompilation. A change in profile is considered
-    // significant if X% (top-k-change-threshold) of the top K%
-    // (top-k-threshold property) samples has changed.
-    parseRuntimeOption("dalvik.vm.profile.top-k-ch-thr",
-                       profileTopKChangeThreshold,
-                       "-Xprofile-top-k-change-threshold:");
-
-    // Type of profile data.
-    parseRuntimeOption("dalvik.vm.profiler.type", profileType, "-Xprofile-type:");
-
-    // Depth of bounded stack data
-    parseRuntimeOption("dalvik.vm.profile.stack-depth",
-                       profileMaxStackDepth,
-                       "-Xprofile-max-stack-depth:");
-
     // Trace files are stored in /data/misc/trace which is writable only in debug mode.
     property_get("ro.debuggable", propBuf, "0");
     if (strcmp(propBuf, "1") == 0) {
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index d04adbf..d7e2c02 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -24,6 +24,7 @@
 #include <android_runtime/Log.h>
 #include <utils/Log.h>
 #include <android/graphics/GraphicsJNI.h>
+#include "ScopedLocalRef.h"
 
 #include "core_jni_helpers.h"
 
@@ -35,6 +36,8 @@
     jfieldID mBitmap;
     jfieldID mHotSpotX;
     jfieldID mHotSpotY;
+    jfieldID mBitmapFrames;
+    jfieldID mDurationPerFrame;
     jmethodID getSystemIcon;
     jmethodID load;
 } gPointerIconClassInfo;
@@ -84,6 +87,19 @@
         env->DeleteLocalRef(bitmapObj);
     }
 
+    ScopedLocalRef<jobjectArray> bitmapFramesObj(env, reinterpret_cast<jobjectArray>(
+            env->GetObjectField(loadedPointerIconObj, gPointerIconClassInfo.mBitmapFrames)));
+    if (bitmapFramesObj.get()) {
+        outPointerIcon->durationPerFrame = env->GetIntField(
+                loadedPointerIconObj, gPointerIconClassInfo.mDurationPerFrame);
+        jsize size = env->GetArrayLength(bitmapFramesObj.get());
+        outPointerIcon->bitmapFrames.resize(size);
+        for (jsize i = 0; i < size; ++i) {
+            ScopedLocalRef<jobject> bitmapObj(env, env->GetObjectArrayElement(bitmapFramesObj.get(), i));
+            GraphicsJNI::getSkBitmap(env, bitmapObj.get(), &(outPointerIcon->bitmapFrames[i]));
+        }
+    }
+
     env->DeleteLocalRef(loadedPointerIconObj);
     return OK;
 }
@@ -121,6 +137,12 @@
     gPointerIconClassInfo.mHotSpotY = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz,
             "mHotSpotY", "F");
 
+    gPointerIconClassInfo.mBitmapFrames = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz,
+            "mBitmapFrames", "[Landroid/graphics/Bitmap;");
+
+    gPointerIconClassInfo.mDurationPerFrame = GetFieldIDOrDie(env, gPointerIconClassInfo.clazz,
+            "mDurationPerFrame", "I");
+
     gPointerIconClassInfo.getSystemIcon = GetStaticMethodIDOrDie(env, gPointerIconClassInfo.clazz,
             "getSystemIcon", "(Landroid/content/Context;I)Landroid/view/PointerIcon;");
 
diff --git a/core/jni/android_view_PointerIcon.h b/core/jni/android_view_PointerIcon.h
index 86f288d..ca08085 100644
--- a/core/jni/android_view_PointerIcon.h
+++ b/core/jni/android_view_PointerIcon.h
@@ -19,6 +19,8 @@
 
 #include "jni.h"
 
+#include <vector>
+
 #include <utils/Errors.h>
 #include <SkBitmap.h>
 
@@ -69,6 +71,8 @@
     SkBitmap bitmap;
     float hotSpotX;
     float hotSpotY;
+    std::vector<SkBitmap> bitmapFrames;
+    int32_t durationPerFrame;
 
     inline bool isNullIcon() {
         return style == POINTER_ICON_STYLE_NULL;
@@ -79,6 +83,8 @@
         bitmap.reset();
         hotSpotX = 0;
         hotSpotY = 0;
+        bitmapFrames.clear();
+        durationPerFrame = 0;
     }
 };
 
diff --git a/core/res/res/drawable-mdpi/pointer_wait_0.png b/core/res/res/drawable-mdpi/pointer_wait_0.png
new file mode 100644
index 0000000..adb7806
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_0.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_1.png b/core/res/res/drawable-mdpi/pointer_wait_1.png
new file mode 100644
index 0000000..fc6b42f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_1.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_10.png b/core/res/res/drawable-mdpi/pointer_wait_10.png
new file mode 100644
index 0000000..02968b5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_10.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_11.png b/core/res/res/drawable-mdpi/pointer_wait_11.png
new file mode 100644
index 0000000..24f866b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_11.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_12.png b/core/res/res/drawable-mdpi/pointer_wait_12.png
new file mode 100644
index 0000000..d1a31bc
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_12.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_13.png b/core/res/res/drawable-mdpi/pointer_wait_13.png
new file mode 100644
index 0000000..b0c6798
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_13.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_14.png b/core/res/res/drawable-mdpi/pointer_wait_14.png
new file mode 100644
index 0000000..721e86d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_14.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_15.png b/core/res/res/drawable-mdpi/pointer_wait_15.png
new file mode 100644
index 0000000..adb0199
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_15.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_16.png b/core/res/res/drawable-mdpi/pointer_wait_16.png
new file mode 100644
index 0000000..3695c18
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_16.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_17.png b/core/res/res/drawable-mdpi/pointer_wait_17.png
new file mode 100644
index 0000000..861605e
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_17.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_18.png b/core/res/res/drawable-mdpi/pointer_wait_18.png
new file mode 100644
index 0000000..f5dfdcf
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_18.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_19.png b/core/res/res/drawable-mdpi/pointer_wait_19.png
new file mode 100644
index 0000000..9d51f79
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_19.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_2.png b/core/res/res/drawable-mdpi/pointer_wait_2.png
new file mode 100644
index 0000000..d73a154
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_2.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_20.png b/core/res/res/drawable-mdpi/pointer_wait_20.png
new file mode 100644
index 0000000..81d1d51
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_20.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_21.png b/core/res/res/drawable-mdpi/pointer_wait_21.png
new file mode 100644
index 0000000..331820b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_21.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_22.png b/core/res/res/drawable-mdpi/pointer_wait_22.png
new file mode 100644
index 0000000..2678d32
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_22.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_23.png b/core/res/res/drawable-mdpi/pointer_wait_23.png
new file mode 100644
index 0000000..d54d9eb
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_23.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_24.png b/core/res/res/drawable-mdpi/pointer_wait_24.png
new file mode 100644
index 0000000..442ace7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_24.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_25.png b/core/res/res/drawable-mdpi/pointer_wait_25.png
new file mode 100644
index 0000000..27ce60d
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_25.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_26.png b/core/res/res/drawable-mdpi/pointer_wait_26.png
new file mode 100644
index 0000000..8143634
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_26.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_27.png b/core/res/res/drawable-mdpi/pointer_wait_27.png
new file mode 100644
index 0000000..496ab9a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_27.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_28.png b/core/res/res/drawable-mdpi/pointer_wait_28.png
new file mode 100644
index 0000000..a2aab2b
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_28.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_29.png b/core/res/res/drawable-mdpi/pointer_wait_29.png
new file mode 100644
index 0000000..646d153
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_29.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_3.png b/core/res/res/drawable-mdpi/pointer_wait_3.png
new file mode 100644
index 0000000..9f45afe
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_3.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_30.png b/core/res/res/drawable-mdpi/pointer_wait_30.png
new file mode 100644
index 0000000..27b3fc4
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_30.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_31.png b/core/res/res/drawable-mdpi/pointer_wait_31.png
new file mode 100644
index 0000000..6dbe184
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_31.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_32.png b/core/res/res/drawable-mdpi/pointer_wait_32.png
new file mode 100644
index 0000000..9f072ef
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_32.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_33.png b/core/res/res/drawable-mdpi/pointer_wait_33.png
new file mode 100644
index 0000000..881ec5f
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_33.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_34.png b/core/res/res/drawable-mdpi/pointer_wait_34.png
new file mode 100644
index 0000000..94961e3
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_34.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_35.png b/core/res/res/drawable-mdpi/pointer_wait_35.png
new file mode 100644
index 0000000..dfa65d7
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_35.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_4.png b/core/res/res/drawable-mdpi/pointer_wait_4.png
new file mode 100644
index 0000000..5d3d652
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_4.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_5.png b/core/res/res/drawable-mdpi/pointer_wait_5.png
new file mode 100644
index 0000000..d440a82
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_5.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_6.png b/core/res/res/drawable-mdpi/pointer_wait_6.png
new file mode 100644
index 0000000..ae65590
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_6.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_7.png b/core/res/res/drawable-mdpi/pointer_wait_7.png
new file mode 100644
index 0000000..cd84aa5
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_7.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_8.png b/core/res/res/drawable-mdpi/pointer_wait_8.png
new file mode 100644
index 0000000..0b81a9a
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_8.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/pointer_wait_9.png b/core/res/res/drawable-mdpi/pointer_wait_9.png
new file mode 100644
index 0000000..c13a90c
--- /dev/null
+++ b/core/res/res/drawable-mdpi/pointer_wait_9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_0.png b/core/res/res/drawable-xhdpi/pointer_wait_0.png
new file mode 100644
index 0000000..5396784
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_0.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_1.png b/core/res/res/drawable-xhdpi/pointer_wait_1.png
new file mode 100644
index 0000000..25edbf5
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_1.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_10.png b/core/res/res/drawable-xhdpi/pointer_wait_10.png
new file mode 100644
index 0000000..96d93a9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_10.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_11.png b/core/res/res/drawable-xhdpi/pointer_wait_11.png
new file mode 100644
index 0000000..cd78675
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_11.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_12.png b/core/res/res/drawable-xhdpi/pointer_wait_12.png
new file mode 100644
index 0000000..1b2c7b2
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_12.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_13.png b/core/res/res/drawable-xhdpi/pointer_wait_13.png
new file mode 100644
index 0000000..3b00f10
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_13.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_14.png b/core/res/res/drawable-xhdpi/pointer_wait_14.png
new file mode 100644
index 0000000..eca5c3f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_14.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_15.png b/core/res/res/drawable-xhdpi/pointer_wait_15.png
new file mode 100644
index 0000000..0fc2085
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_15.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_16.png b/core/res/res/drawable-xhdpi/pointer_wait_16.png
new file mode 100644
index 0000000..db13cf6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_16.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_17.png b/core/res/res/drawable-xhdpi/pointer_wait_17.png
new file mode 100644
index 0000000..9b6fac5
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_17.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_18.png b/core/res/res/drawable-xhdpi/pointer_wait_18.png
new file mode 100644
index 0000000..c56ff6c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_18.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_19.png b/core/res/res/drawable-xhdpi/pointer_wait_19.png
new file mode 100644
index 0000000..22b7c90
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_19.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_2.png b/core/res/res/drawable-xhdpi/pointer_wait_2.png
new file mode 100644
index 0000000..4bdbe3f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_2.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_20.png b/core/res/res/drawable-xhdpi/pointer_wait_20.png
new file mode 100644
index 0000000..6d042fb
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_20.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_21.png b/core/res/res/drawable-xhdpi/pointer_wait_21.png
new file mode 100644
index 0000000..e3ab63f
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_21.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_22.png b/core/res/res/drawable-xhdpi/pointer_wait_22.png
new file mode 100644
index 0000000..b25f6b7d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_22.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_23.png b/core/res/res/drawable-xhdpi/pointer_wait_23.png
new file mode 100644
index 0000000..49faba9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_23.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_24.png b/core/res/res/drawable-xhdpi/pointer_wait_24.png
new file mode 100644
index 0000000..e91c340
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_24.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_25.png b/core/res/res/drawable-xhdpi/pointer_wait_25.png
new file mode 100644
index 0000000..f4785c6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_25.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_26.png b/core/res/res/drawable-xhdpi/pointer_wait_26.png
new file mode 100644
index 0000000..ea902f8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_26.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_27.png b/core/res/res/drawable-xhdpi/pointer_wait_27.png
new file mode 100644
index 0000000..7d628c3
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_27.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_28.png b/core/res/res/drawable-xhdpi/pointer_wait_28.png
new file mode 100644
index 0000000..92d6dc1
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_28.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_29.png b/core/res/res/drawable-xhdpi/pointer_wait_29.png
new file mode 100644
index 0000000..5a8d189
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_29.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_3.png b/core/res/res/drawable-xhdpi/pointer_wait_3.png
new file mode 100644
index 0000000..de4d79c
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_3.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_30.png b/core/res/res/drawable-xhdpi/pointer_wait_30.png
new file mode 100644
index 0000000..ba04b5e
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_30.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_31.png b/core/res/res/drawable-xhdpi/pointer_wait_31.png
new file mode 100644
index 0000000..3ef8e98
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_31.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_32.png b/core/res/res/drawable-xhdpi/pointer_wait_32.png
new file mode 100644
index 0000000..3297a7d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_32.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_33.png b/core/res/res/drawable-xhdpi/pointer_wait_33.png
new file mode 100644
index 0000000..b0ac3b9
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_33.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_34.png b/core/res/res/drawable-xhdpi/pointer_wait_34.png
new file mode 100644
index 0000000..0eaa386
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_34.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_35.png b/core/res/res/drawable-xhdpi/pointer_wait_35.png
new file mode 100644
index 0000000..73894d8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_35.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_4.png b/core/res/res/drawable-xhdpi/pointer_wait_4.png
new file mode 100644
index 0000000..ea44e85
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_4.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_5.png b/core/res/res/drawable-xhdpi/pointer_wait_5.png
new file mode 100644
index 0000000..46c399d
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_5.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_6.png b/core/res/res/drawable-xhdpi/pointer_wait_6.png
new file mode 100644
index 0000000..3b9aff6
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_6.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_7.png b/core/res/res/drawable-xhdpi/pointer_wait_7.png
new file mode 100644
index 0000000..a54edc0
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_7.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_8.png b/core/res/res/drawable-xhdpi/pointer_wait_8.png
new file mode 100644
index 0000000..2f30732
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_8.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/pointer_wait_9.png b/core/res/res/drawable-xhdpi/pointer_wait_9.png
new file mode 100644
index 0000000..f39c7a7
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/pointer_wait_9.png
Binary files differ
diff --git a/core/res/res/drawable/pointer_wait.xml b/core/res/res/drawable/pointer_wait.xml
new file mode 100644
index 0000000..8955ce8
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false">
+  <item android:drawable="@drawable/pointer_wait_1" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_2" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_3" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_4" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_5" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_6" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_7" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_8" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_9" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_10" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_11" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_12" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_13" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_14" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_15" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_16" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_17" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_18" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_19" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_20" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_21" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_22" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_23" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_24" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_25" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_26" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_27" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_28" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_29" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_30" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_31" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_32" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_33" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_34" android:duration="25"/>
+  <item android:drawable="@drawable/pointer_wait_35" android:duration="25"/>
+</animation-list>
diff --git a/core/res/res/drawable/pointer_wait_icon.xml b/core/res/res/drawable/pointer_wait_icon.xml
new file mode 100644
index 0000000..d9b03b0
--- /dev/null
+++ b/core/res/res/drawable/pointer_wait_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<pointer-icon xmlns:android="http://schemas.android.com/apk/res/android"
+    android:bitmap="@drawable/pointer_wait"
+    android:hotSpotX="7dp"
+    android:hotSpotY="7dp" />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 90fc22b..0f817f3 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -7631,6 +7631,8 @@
         <attr name="pointerIconHand" format="reference"/>
         <!-- Reference to a pointer drawable with STYLE_HELP -->
         <attr name="pointerIconHelp" format="reference"/>
+        <!-- Reference to a pointer drawable with STYLE_WAIT -->
+        <attr name="pointerIconWait" format="reference"/>
         <!-- Reference to a pointer drawable with STYLE_CELL -->
         <attr name="pointerIconCell" format="reference"/>
         <!-- Reference to a pointer drawable with STYLE_CROSSHAIR -->
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index b831df8..eb99077 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1339,6 +1339,7 @@
         <item name="pointerIconHand">@drawable/pointer_hand_icon</item>
         <item name="pointerIconContextMenu">@drawable/pointer_context_menu_icon</item>
         <item name="pointerIconHelp">@drawable/pointer_help_icon</item>
+        <item name="pointerIconWait">@drawable/pointer_wait_icon</item>
         <item name="pointerIconCell">@drawable/pointer_cell_icon</item>
         <item name="pointerIconCrosshair">@drawable/pointer_crosshair_icon</item>
         <item name="pointerIconText">@drawable/pointer_text_icon</item>
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index c31a8b7..8c20ddc 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -101,20 +101,21 @@
      */
     public static void install() {
         Provider[] providers = Security.getProviders();
-        int bcProviderPosition = -1;
-        for (int position = 0; position < providers.length; position++) {
-            Provider provider = providers[position];
+        int bcProviderIndex = -1;
+        for (int i = 0; i < providers.length; i++) {
+            Provider provider = providers[i];
             if ("BC".equals(provider.getName())) {
-                bcProviderPosition = position;
+                bcProviderIndex = i;
                 break;
             }
         }
 
         Security.addProvider(new AndroidKeyStoreProvider());
         Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
-        if (bcProviderPosition != -1) {
+        if (bcProviderIndex != -1) {
             // Bouncy Castle provider found -- install the workaround provider above it.
-            Security.insertProviderAt(workaroundProvider, bcProviderPosition);
+            // insertProviderAt uses 1-based positions.
+            Security.insertProviderAt(workaroundProvider, bcProviderIndex + 1);
         } else {
             // Bouncy Castle provider not found -- install the workaround provider at lowest
             // priority.
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 39b7ecb..4cfbb2a 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -18,6 +18,7 @@
 #include "Extensions.h"
 
 #include <GLES2/gl2.h>
+#include <log/log.h>
 
 #include <thread>
 #include <mutex>
@@ -29,6 +30,7 @@
 static std::once_flag sInitializedFlag;
 
 const DeviceInfo* DeviceInfo::get() {
+    LOG_ALWAYS_FATAL_IF(!sDeviceInfo, "DeviceInfo not yet initialized.");
     return sDeviceInfo;
 }
 
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index b04f16f..96cac7e 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -21,10 +21,10 @@
 #include "renderstate/OffscreenBufferPool.h"
 #include "utils/FatVector.h"
 #include "utils/PaintUtils.h"
+#include "utils/TraceUtils.h"
 
 #include <SkCanvas.h>
 #include <SkPathOps.h>
-#include <utils/Trace.h>
 #include <utils/TypeHelpers.h>
 
 namespace android {
@@ -331,13 +331,15 @@
         RenderNode* layerNode = layers.entries()[i].renderNode;
         const Rect& layerDamage = layers.entries()[i].damage;
 
-        saveForLayer(layerNode->getWidth(), layerNode->getHeight(),
-                layerDamage, nullptr, layerNode);
-        mCanvasState.writableSnapshot()->setClip(
-                layerDamage.left, layerDamage.top, layerDamage.right, layerDamage.bottom);
+        // map current light center into RenderNode's coordinate space
+        Vector3 lightCenter = mCanvasState.currentSnapshot()->getRelativeLightCenter();
+        layerNode->getLayer()->inverseTransformInWindow.mapPoint3d(lightCenter);
+
+        saveForLayer(layerNode->getWidth(), layerNode->getHeight(), 0, 0,
+                layerDamage, lightCenter, nullptr, layerNode);
 
         if (layerNode->getDisplayList()) {
-            deferImpl(*(layerNode->getDisplayList()));
+            deferDisplayList(*(layerNode->getDisplayList()));
         }
         restoreForLayer();
     }
@@ -363,7 +365,7 @@
     mCanvasState.initializeSaveStack(viewportWidth, viewportHeight,
             0, 0, viewportWidth, viewportHeight, lightCenter);
 
-    deferImpl(displayList);
+    deferDisplayList(displayList);
 }
 
 void OpReorderer::onViewportInitialized() {}
@@ -371,18 +373,99 @@
 void OpReorderer::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {}
 
 void OpReorderer::deferNodePropsAndOps(RenderNode& node) {
-    if (node.applyViewProperties(mCanvasState, mAllocator)) {
-        // not rejected so render
+    const RenderProperties& properties = node.properties();
+    const Outline& outline = properties.getOutline();
+    if (properties.getAlpha() <= 0
+            || (outline.getShouldClip() && outline.isEmpty())
+            || properties.getScaleX() == 0
+            || properties.getScaleY() == 0) {
+        return; // rejected
+    }
+
+    if (properties.getLeft() != 0 || properties.getTop() != 0) {
+        mCanvasState.translate(properties.getLeft(), properties.getTop());
+    }
+    if (properties.getStaticMatrix()) {
+        mCanvasState.concatMatrix(*properties.getStaticMatrix());
+    } else if (properties.getAnimationMatrix()) {
+        mCanvasState.concatMatrix(*properties.getAnimationMatrix());
+    }
+    if (properties.hasTransformMatrix()) {
+        if (properties.isTransformTranslateOnly()) {
+            mCanvasState.translate(properties.getTranslationX(), properties.getTranslationY());
+        } else {
+            mCanvasState.concatMatrix(*properties.getTransformMatrix());
+        }
+    }
+
+    const int width = properties.getWidth();
+    const int height = properties.getHeight();
+
+    Rect saveLayerBounds; // will be set to non-empty if saveLayer needed
+    const bool isLayer = properties.effectiveLayerType() != LayerType::None;
+    int clipFlags = properties.getClippingFlags();
+    if (properties.getAlpha() < 1) {
+        if (isLayer) {
+            clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
+        }
+        if (CC_LIKELY(isLayer || !properties.getHasOverlappingRendering())) {
+            // simply scale rendering content's alpha
+            mCanvasState.scaleAlpha(properties.getAlpha());
+        } else {
+            // schedule saveLayer by initializing saveLayerBounds
+            saveLayerBounds.set(0, 0, width, height);
+            if (clipFlags) {
+                properties.getClippingRectForFlags(clipFlags, &saveLayerBounds);
+                clipFlags = 0; // all clipping done by savelayer
+            }
+        }
+
+        if (CC_UNLIKELY(ATRACE_ENABLED() && properties.promotedToLayer())) {
+            // pretend alpha always causes savelayer to warn about
+            // performance problem affecting old versions
+            ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", node.getName(), width, height);
+        }
+    }
+    if (clipFlags) {
+        Rect clipRect;
+        properties.getClippingRectForFlags(clipFlags, &clipRect);
+        mCanvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
+                SkRegion::kIntersect_Op);
+    }
+
+    if (properties.getRevealClip().willClip()) {
+        Rect bounds;
+        properties.getRevealClip().getBounds(&bounds);
+        mCanvasState.setClippingRoundRect(mAllocator,
+                bounds, properties.getRevealClip().getRadius());
+    } else if (properties.getOutline().willClip()) {
+        mCanvasState.setClippingOutline(mAllocator, &(properties.getOutline()));
+    }
+
+    if (!mCanvasState.quickRejectConservative(0, 0, width, height)) {
+        // not rejected, so defer render as either Layer, or direct (possibly wrapped in saveLayer)
         if (node.getLayer()) {
             // HW layer
             LayerOp* drawLayerOp = new (mAllocator) LayerOp(node);
             BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
             if (bakedOpState) {
-                // Layer will be drawn into parent layer (which is now current, since we popped mLayerStack)
+                // Node's layer already deferred, schedule it to render into parent layer
                 currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Bitmap);
             }
+        } else if (CC_UNLIKELY(!saveLayerBounds.isEmpty())) {
+            // draw DisplayList contents within temporary, since persisted layer could not be used.
+            // (temp layers are clipped to viewport, since they don't persist offscreen content)
+            SkPaint saveLayerPaint;
+            saveLayerPaint.setAlpha(properties.getAlpha());
+            onBeginLayerOp(*new (mAllocator) BeginLayerOp(
+                    saveLayerBounds,
+                    Matrix4::identity(),
+                    saveLayerBounds,
+                    &saveLayerPaint));
+            deferDisplayList(*(node.getDisplayList()));
+            onEndLayerOp(*new (mAllocator) EndLayerOp());
         } else {
-            deferImpl(*(node.getDisplayList()));
+            deferDisplayList(*(node.getDisplayList()));
         }
     }
 }
@@ -535,7 +618,7 @@
  */
 #define OP_RECEIVER(Type) \
         [](OpReorderer& reorderer, const RecordedOp& op) { reorderer.on##Type(static_cast<const Type&>(op)); },
-void OpReorderer::deferImpl(const DisplayList& displayList) {
+void OpReorderer::deferDisplayList(const DisplayList& displayList) {
     static std::function<void(OpReorderer& reorderer, const RecordedOp&)> receivers[] = {
         MAP_OPS(OP_RECEIVER)
     };
@@ -600,34 +683,21 @@
     currentLayer().deferUnmergeableOp(mAllocator, bakedStateOp, OpBatchType::Vertices);
 }
 
-void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight, const Rect& repaintRect,
+void OpReorderer::saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
+        float contentTranslateX, float contentTranslateY,
+        const Rect& repaintRect,
+        const Vector3& lightCenter,
         const BeginLayerOp* beginLayerOp, RenderNode* renderNode) {
-
-    auto previous = mCanvasState.currentSnapshot();
     mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
-    mCanvasState.writableSnapshot()->transform->loadIdentity();
     mCanvasState.writableSnapshot()->initializeViewport(layerWidth, layerHeight);
     mCanvasState.writableSnapshot()->roundRectClipState = nullptr;
-
-    Vector3 lightCenter = previous->getRelativeLightCenter();
-    if (renderNode) {
-        Matrix4& inverse = renderNode->getLayer()->inverseTransformInWindow;
-        inverse.mapPoint3d(lightCenter);
-    } else {
-        // Combine all transforms used to present saveLayer content:
-        // parent content transform * canvas transform * bounds offset
-        Matrix4 contentTransform(*previous->transform);
-        contentTransform.multiply(beginLayerOp->localMatrix);
-        contentTransform.translate(beginLayerOp->unmappedBounds.left, beginLayerOp->unmappedBounds.top);
-
-        // inverse the total transform, to map light center into layer-relative space
-        Matrix4 inverse;
-        inverse.loadInverse(contentTransform);
-        inverse.mapPoint3d(lightCenter);
-    }
     mCanvasState.writableSnapshot()->setRelativeLightCenter(lightCenter);
+    mCanvasState.writableSnapshot()->transform->loadTranslate(
+            contentTranslateX, contentTranslateY, 0);
+    mCanvasState.writableSnapshot()->setClip(
+            repaintRect.left, repaintRect.top, repaintRect.right, repaintRect.bottom);
 
-    // create a new layer, and push its index on the stack
+    // create a new layer repaint, and push its index on the stack
     mLayerStack.push_back(mLayerReorderers.size());
     mLayerReorderers.emplace_back(layerWidth, layerHeight, repaintRect, beginLayerOp, renderNode);
 }
@@ -640,9 +710,48 @@
 
 // TODO: test rejection at defer time, where the bounds become empty
 void OpReorderer::onBeginLayerOp(const BeginLayerOp& op) {
-    const uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
-    const uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
-    saveForLayer(layerWidth, layerHeight, Rect(layerWidth, layerHeight), &op, nullptr);
+    uint32_t layerWidth = (uint32_t) op.unmappedBounds.getWidth();
+    uint32_t layerHeight = (uint32_t) op.unmappedBounds.getHeight();
+
+    auto previous = mCanvasState.currentSnapshot();
+    Vector3 lightCenter = previous->getRelativeLightCenter();
+
+    // Combine all transforms used to present saveLayer content:
+    // parent content transform * canvas transform * bounds offset
+    Matrix4 contentTransform(*previous->transform);
+    contentTransform.multiply(op.localMatrix);
+    contentTransform.translate(op.unmappedBounds.left, op.unmappedBounds.top);
+
+    Matrix4 inverseContentTransform;
+    inverseContentTransform.loadInverse(contentTransform);
+
+    // map the light center into layer-relative space
+    inverseContentTransform.mapPoint3d(lightCenter);
+
+    // Clip bounds of temporary layer to parent's clip rect, so:
+    Rect saveLayerBounds(layerWidth, layerHeight);
+    //     1) transform Rect(width, height) into parent's space
+    //        note: left/top offsets put in contentTransform above
+    contentTransform.mapRect(saveLayerBounds);
+    //     2) intersect with parent's clip
+    saveLayerBounds.doIntersect(previous->getRenderTargetClip());
+    //     3) and transform back
+    inverseContentTransform.mapRect(saveLayerBounds);
+    saveLayerBounds.doIntersect(Rect(layerWidth, layerHeight));
+    saveLayerBounds.roundOut();
+
+    // if bounds are reduced, will clip the layer's area by reducing required bounds...
+    layerWidth = saveLayerBounds.getWidth();
+    layerHeight = saveLayerBounds.getHeight();
+    // ...and shifting drawing content to account for left/top side clipping
+    float contentTranslateX = -saveLayerBounds.left;
+    float contentTranslateY = -saveLayerBounds.top;
+
+    saveForLayer(layerWidth, layerHeight,
+            contentTranslateX, contentTranslateY,
+            Rect(layerWidth, layerHeight),
+            lightCenter,
+            &op, nullptr);
 }
 
 void OpReorderer::onEndLayerOp(const EndLayerOp& /* ignored */) {
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
index 09d5cbc..976f413 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -190,7 +190,10 @@
         Positive
     };
     void saveForLayer(uint32_t layerWidth, uint32_t layerHeight,
-            const Rect& repaintRect, const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
+            float contentTranslateX, float contentTranslateY,
+            const Rect& repaintRect,
+            const Vector3& lightCenter,
+            const BeginLayerOp* beginLayerOp, RenderNode* renderNode);
     void restoreForLayer();
 
     LayerReorderer& currentLayer() { return mLayerReorderers[mLayerStack.back()]; }
@@ -204,7 +207,7 @@
 
     void deferShadow(const RenderNodeOp& casterOp);
 
-    void deferImpl(const DisplayList& displayList);
+    void deferDisplayList(const DisplayList& displayList);
 
     template <typename V>
     void defer3dChildren(ChildrenSelectMode mode, const V& zTranslatedNodes);
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index 50199db..0736a10 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -276,7 +276,7 @@
     }
 
     void dump(const char* label = nullptr) const {
-        ALOGD("%s[l=%f t=%f r=%f b=%f]", label ? label : "Rect", left, top, right, bottom);
+        ALOGD("%s[l=%.2f t=%.2f r=%.2f b=%.2f]", label ? label : "Rect", left, top, right, bottom);
     }
 }; // class Rect
 
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index 2713f46..716d536 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -524,76 +524,6 @@
     }
 }
 
-bool RenderNode::applyViewProperties(CanvasState& canvasState, LinearAllocator& allocator) const {
-    const Outline& outline = properties().getOutline();
-    if (properties().getAlpha() <= 0
-            || (outline.getShouldClip() && outline.isEmpty())
-            || properties().getScaleX() == 0
-            || properties().getScaleY() == 0) {
-        return false; // rejected
-    }
-
-    if (properties().getLeft() != 0 || properties().getTop() != 0) {
-        canvasState.translate(properties().getLeft(), properties().getTop());
-    }
-    if (properties().getStaticMatrix()) {
-        canvasState.concatMatrix(*properties().getStaticMatrix());
-    } else if (properties().getAnimationMatrix()) {
-        canvasState.concatMatrix(*properties().getAnimationMatrix());
-    }
-    if (properties().hasTransformMatrix()) {
-        if (properties().isTransformTranslateOnly()) {
-            canvasState.translate(properties().getTranslationX(), properties().getTranslationY());
-        } else {
-            canvasState.concatMatrix(*properties().getTransformMatrix());
-        }
-    }
-
-    const bool isLayer = properties().effectiveLayerType() != LayerType::None;
-    int clipFlags = properties().getClippingFlags();
-    if (properties().getAlpha() < 1) {
-        if (isLayer) {
-            clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
-        }
-        if (CC_LIKELY(isLayer || !properties().getHasOverlappingRendering())) {
-            // simply scale rendering content's alpha
-            canvasState.scaleAlpha(properties().getAlpha());
-        } else {
-            // savelayer needed to create an offscreen buffer
-            Rect layerBounds(0, 0, getWidth(), getHeight());
-            if (clipFlags) {
-                properties().getClippingRectForFlags(clipFlags, &layerBounds);
-                clipFlags = 0; // all clipping done by savelayer
-            }
-            LOG_ALWAYS_FATAL("TODO: savelayer");
-        }
-
-        if (CC_UNLIKELY(ATRACE_ENABLED() && properties().promotedToLayer())) {
-            // pretend alpha always causes savelayer to warn about
-            // performance problem affecting old versions
-            ATRACE_FORMAT("%s alpha caused saveLayer %dx%d", getName(), getWidth(), getHeight());
-        }
-    }
-    if (clipFlags) {
-        Rect clipRect;
-        properties().getClippingRectForFlags(clipFlags, &clipRect);
-        canvasState.clipRect(clipRect.left, clipRect.top, clipRect.right, clipRect.bottom,
-                SkRegion::kIntersect_Op);
-    }
-
-    // TODO: support nesting round rect clips
-    if (mProperties.getRevealClip().willClip()) {
-        Rect bounds;
-        mProperties.getRevealClip().getBounds(&bounds);
-        canvasState.setClippingRoundRect(allocator,
-                bounds, mProperties.getRevealClip().getRadius());
-    } else if (mProperties.getOutline().willClip()) {
-        canvasState.setClippingOutline(allocator, &(mProperties.getOutline()));
-    }
-    return !canvasState.quickRejectConservative(
-            0, 0, properties().getWidth(), properties().getHeight());
-}
-
 /*
  * For property operations, we pass a savecount of 0, since the operations aren't part of the
  * displaylist, and thus don't have to compensate for the record-time/playback-time discrepancy in
diff --git a/libs/hwui/RenderNode.h b/libs/hwui/RenderNode.h
index bae5ebe..83d1b58 100644
--- a/libs/hwui/RenderNode.h
+++ b/libs/hwui/RenderNode.h
@@ -187,9 +187,6 @@
 
     AnimatorManager& animators() { return mAnimatorManager; }
 
-    // Returns false if the properties dictate the subtree contained in this RenderNode won't render
-    bool applyViewProperties(CanvasState& canvasState, LinearAllocator& allocator) const;
-
     void applyViewPropertyTransforms(mat4& matrix, bool true3dTransform = false) const;
 
     bool nothingToDraw() const {
diff --git a/libs/hwui/RenderProperties.h b/libs/hwui/RenderProperties.h
index 0bd5b65..3952798 100644
--- a/libs/hwui/RenderProperties.h
+++ b/libs/hwui/RenderProperties.h
@@ -610,7 +610,6 @@
 
     bool fitsOnLayer() const {
         const DeviceInfo* deviceInfo = DeviceInfo::get();
-        LOG_ALWAYS_FATAL_IF(!deviceInfo, "DeviceInfo uninitialized");
         return mPrimitiveFields.mWidth <= deviceInfo->maxTextureSize()
                         && mPrimitiveFields.mHeight <= deviceInfo->maxTextureSize();
     }
diff --git a/libs/hwui/unit_tests/OpReordererTests.cpp b/libs/hwui/unit_tests/OpReordererTests.cpp
index a8c9bba..07a1855 100644
--- a/libs/hwui/unit_tests/OpReordererTests.cpp
+++ b/libs/hwui/unit_tests/OpReordererTests.cpp
@@ -17,10 +17,10 @@
 #include <gtest/gtest.h>
 
 #include <BakedOpState.h>
+#include <LayerUpdateQueue.h>
 #include <OpReorderer.h>
 #include <RecordedOp.h>
 #include <RecordingCanvas.h>
-#include <renderthread/CanvasContext.h> // todo: remove
 #include <unit_tests/TestUtils.h>
 
 #include <unordered_map>
@@ -28,8 +28,8 @@
 namespace android {
 namespace uirenderer {
 
-LayerUpdateQueue sEmptyLayerUpdateQueue;
-Vector3 sLightCenter = {100, 100, 100};
+const LayerUpdateQueue sEmptyLayerUpdateQueue;
+const Vector3 sLightCenter = {100, 100, 100};
 
 static std::vector<sp<RenderNode>> createSyncedNodeList(sp<RenderNode>& node) {
     TestUtils::syncHierarchyPropertiesAndDisplayList(node);
@@ -79,7 +79,7 @@
 
 /**
  * Dispatches all static methods to similar formed methods on renderer, which fail by default but
- * are overriden by subclasses per test.
+ * are overridden by subclasses per test.
  */
 class TestDispatcher {
 public:
@@ -117,7 +117,6 @@
         canvas.drawBitmap(bitmap, 10, 10, nullptr);
     });
     OpReorderer reorderer(100, 200, *dl, sLightCenter);
-
     SimpleTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
@@ -163,7 +162,6 @@
     });
 
     OpReorderer reorderer(200, 200, *dl, sLightCenter);
-
     SimpleBatchingTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(2 * SIMPLE_BATCHING_LOOPS, renderer.getIndex()); // 2 x loops ops, because no merging (TODO: force no merging)
@@ -208,7 +206,6 @@
 
     OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
             createSyncedNodeList(parent), sLightCenter);
-
     RenderNodeTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
 }
@@ -232,7 +229,6 @@
     OpReorderer reorderer(sEmptyLayerUpdateQueue,
             SkRect::MakeLTRB(10, 20, 30, 40), // clip to small area, should see in receiver
             200, 200, createSyncedNodeList(node), sLightCenter);
-
     ClippedTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
 }
@@ -274,7 +270,6 @@
     });
 
     OpReorderer reorderer(200, 200, *dl, sLightCenter);
-
     SaveLayerSimpleTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex());
@@ -345,7 +340,6 @@
     });
 
     OpReorderer reorderer(800, 800, *dl, sLightCenter);
-
     SaveLayerNestedTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(10, renderer.getIndex());
@@ -520,7 +514,6 @@
 
     OpReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
             syncedList, sLightCenter);
-
     HwLayerComplexTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(13, renderer.getIndex());
@@ -570,7 +563,6 @@
     });
     OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 100, 100,
             createSyncedNodeList(parent), sLightCenter);
-
     ZReorderTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(10, renderer.getIndex());
@@ -616,7 +608,6 @@
 
     OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
             createSyncedNodeList(parent), sLightCenter);
-
     ShadowTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(2, renderer.getIndex());
@@ -658,7 +649,6 @@
 
     OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
             createSyncedNodeList(parent), (Vector3) { 100, 100, 100 });
-
     ShadowSaveLayerTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(5, renderer.getIndex());
@@ -708,7 +698,6 @@
     layerUpdateQueue.enqueueLayerWithDamage(parent.get(), Rect(100, 100));
     OpReorderer reorderer(layerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
             syncedList, (Vector3) { 100, 100, 100 });
-
     ShadowHwLayerTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(5, renderer.getIndex());
@@ -738,13 +727,11 @@
 
     OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200,
             createSyncedNodeList(parent), sLightCenter);
-
     ShadowLayeringTestRenderer renderer;
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-
 static void testProperty(TestUtils::PropSetupCallback propSetupCallback,
         std::function<void(const RectOp&, const BakedOpState&)> opValidateCallback) {
     class PropertyTestRenderer : public TestRendererBase {
@@ -766,7 +753,6 @@
 
     OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(100, 100), 200, 200,
             createSyncedNodeList(node), sLightCenter);
-
     PropertyTestRenderer renderer(opValidateCallback);
     reorderer.replayBakedOps<TestDispatcher>(renderer);
     EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
@@ -854,5 +840,128 @@
     });
 }
 
+struct SaveLayerAlphaData {
+    uint32_t layerWidth = 0;
+    uint32_t layerHeight = 0;
+    Rect rectClippedBounds;
+    Matrix4 rectMatrix;
+};
+/**
+ * Constructs a view to hit the temporary layer alpha property implementation:
+ *     a) 0 < alpha < 1
+ *     b) too big for layer (larger than maxTextureSize)
+ *     c) overlapping rendering content
+ * returning observed data about layer size and content clip/transform.
+ *
+ * Used to validate clipping behavior of temporary layer, where requested layer size is reduced
+ * (for efficiency, and to fit in layer size constraints) based on parent clip.
+ */
+void testSaveLayerAlphaClip(SaveLayerAlphaData* outObservedData,
+        TestUtils::PropSetupCallback propSetupCallback) {
+    class SaveLayerAlphaClipTestRenderer : public TestRendererBase {
+    public:
+        SaveLayerAlphaClipTestRenderer(SaveLayerAlphaData* outData)
+                : mOutData(outData) {}
+
+        OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
+            EXPECT_EQ(0, mIndex++);
+            mOutData->layerWidth = width;
+            mOutData->layerHeight = height;
+            return nullptr;
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+
+            mOutData->rectClippedBounds = state.computedState.clippedBounds;
+            mOutData->rectMatrix = state.computedState.transform;
+        }
+        void endLayer() override {
+            EXPECT_EQ(2, mIndex++);
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(3, mIndex++);
+        }
+    private:
+        SaveLayerAlphaData* mOutData;
+    };
+
+    ASSERT_GT(10000, DeviceInfo::get()->maxTextureSize())
+            << "Node must be bigger than max texture size to exercise saveLayer codepath";
+    auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 10000, 10000, [](RecordingCanvas& canvas) {
+        SkPaint paint;
+        paint.setColor(SK_ColorWHITE);
+        canvas.drawRect(0, 0, 10000, 10000, paint);
+    }, [&propSetupCallback](RenderProperties& properties) {
+        properties.setHasOverlappingRendering(true);
+        properties.setAlpha(0.5f); // force saveLayer, since too big for HW layer
+
+        // apply other properties
+        int flags = propSetupCallback(properties);
+        return RenderNode::GENERIC | RenderNode::ALPHA | flags;
+    });
+    auto nodes = createSyncedNodeList(node); // sync before querying height
+
+    OpReorderer reorderer(sEmptyLayerUpdateQueue, SkRect::MakeWH(200, 200), 200, 200, nodes, sLightCenter);
+    SaveLayerAlphaClipTestRenderer renderer(outObservedData);
+    reorderer.replayBakedOps<TestDispatcher>(renderer);
+
+    // assert, since output won't be valid if we haven't seen a save layer triggered
+    ASSERT_EQ(4, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
+}
+
+TEST(OpReorderer, renderPropSaveLayerAlphaClipBig) {
+    SaveLayerAlphaData observedData;
+    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
+        properties.setTranslationX(10); // offset rendering content
+        properties.setTranslationY(-2000); // offset rendering content
+        return RenderNode::TRANSLATION_X | RenderNode::TRANSLATION_Y;
+    });
+    EXPECT_EQ(190u, observedData.layerWidth);
+    EXPECT_EQ(200u, observedData.layerHeight);
+    EXPECT_EQ(Rect(0, 0, 190, 200), observedData.rectClippedBounds)
+            << "expect content to be clipped to screen area";
+    Matrix4 expected;
+    expected.loadTranslate(0, -2000, 0);
+    EXPECT_MATRIX_APPROX_EQ(expected, observedData.rectMatrix)
+            << "expect content to be translated as part of being clipped";
+}
+
+TEST(OpReorderer, renderPropSaveLayerAlphaRotate) {
+    SaveLayerAlphaData observedData;
+    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
+        // Translate and rotate the view so that the only visible part is the top left corner of
+        // the view. It will form an isoceles right triangle with a long side length of 200 at the
+        // bottom of the viewport.
+        properties.setTranslationX(100);
+        properties.setTranslationY(100);
+        properties.setPivotX(0);
+        properties.setPivotY(0);
+        properties.setRotation(45);
+        return RenderNode::GENERIC
+                | RenderNode::TRANSLATION_X | RenderNode::TRANSLATION_Y
+                | RenderNode::ROTATION;
+    });
+    // ceil(sqrt(2) / 2 * 200) = 142
+    EXPECT_EQ(142u, observedData.layerWidth);
+    EXPECT_EQ(142u, observedData.layerHeight);
+    EXPECT_EQ(Rect(0, 0, 142, 142), observedData.rectClippedBounds);
+    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
+}
+
+TEST(OpReorderer, renderPropSaveLayerAlphaScale) {
+    SaveLayerAlphaData observedData;
+    testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
+        properties.setPivotX(0);
+        properties.setPivotY(0);
+        properties.setScaleX(2);
+        properties.setScaleY(0.5f);
+        return RenderNode::GENERIC | RenderNode::SCALE_X | RenderNode::SCALE_Y;
+    });
+    EXPECT_EQ(100u, observedData.layerWidth);
+    EXPECT_EQ(400u, observedData.layerHeight);
+    EXPECT_EQ(Rect(0, 0, 100, 400), observedData.rectClippedBounds);
+    EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
+}
+
 } // namespace uirenderer
 } // namespace android
diff --git a/libs/input/PointerController.cpp b/libs/input/PointerController.cpp
index c9586e4..bd6af78 100644
--- a/libs/input/PointerController.cpp
+++ b/libs/input/PointerController.cpp
@@ -86,6 +86,9 @@
     mLocked.pointerIconChanged = false;
     mLocked.requestedPointerShape = mPolicy->getDefaultPointerIconId();
 
+    mLocked.animationFrameIndex = 0;
+    mLocked.lastFrameUpdatedTime = 0;
+
     mLocked.buttonState = 0;
 
     loadResources();
@@ -239,7 +242,8 @@
     AutoMutex _l(mLock);
 
     if (presentation == PRESENTATION_POINTER && mLocked.additionalMouseResources.empty()) {
-        mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources);
+        mPolicy->loadAdditionalMouseResources(&mLocked.additionalMouseResources,
+                                              &mLocked.animationResources);
     }
 
     if (mLocked.presentation != presentation) {
@@ -402,7 +406,7 @@
     updatePointerLocked();
 }
 
-void PointerController::updatePointerShape(int iconId) {
+void PointerController::updatePointerShape(int32_t iconId) {
     AutoMutex _l(mLock);
     if (mLocked.requestedPointerShape != iconId) {
         mLocked.requestedPointerShape = iconId;
@@ -462,8 +466,17 @@
 void PointerController::doAnimate(nsecs_t timestamp) {
     AutoMutex _l(mLock);
 
-    bool keepAnimating = false;
     mLocked.animationPending = false;
+
+    bool keepFading = doFadingAnimationLocked(timestamp);
+    bool keepBitmapFlipping = doBitmapAnimationLocked(timestamp);
+    if (keepFading || keepBitmapFlipping) {
+        startAnimationLocked();
+    }
+}
+
+bool PointerController::doFadingAnimationLocked(nsecs_t timestamp) {
+    bool keepAnimating = false;
     nsecs_t frameDelay = timestamp - mLocked.animationTime;
 
     // Animate pointer fade.
@@ -501,10 +514,32 @@
             }
         }
     }
+    return keepAnimating;
+}
 
-    if (keepAnimating) {
-        startAnimationLocked();
+bool PointerController::doBitmapAnimationLocked(nsecs_t timestamp) {
+    std::map<int32_t, PointerAnimation>::const_iterator iter = mLocked.animationResources.find(
+            mLocked.requestedPointerShape);
+    if (iter == mLocked.animationResources.end()) {
+        return false;
     }
+
+    if (timestamp - mLocked.lastFrameUpdatedTime > iter->second.durationPerFrame) {
+        mSpriteController->openTransaction();
+
+        int incr = (timestamp - mLocked.lastFrameUpdatedTime) / iter->second.durationPerFrame;
+        mLocked.animationFrameIndex += incr;
+        mLocked.lastFrameUpdatedTime += iter->second.durationPerFrame * incr;
+        while (mLocked.animationFrameIndex >= iter->second.animationFrames.size()) {
+            mLocked.animationFrameIndex -= iter->second.animationFrames.size();
+        }
+        mLocked.pointerSprite->setIcon(iter->second.animationFrames[mLocked.animationFrameIndex]);
+
+        mSpriteController->closeTransaction();
+    }
+
+    // Keep animating.
+    return true;
 }
 
 void PointerController::doInactivityTimeout() {
@@ -549,9 +584,16 @@
             if (mLocked.requestedPointerShape == mPolicy->getDefaultPointerIconId()) {
                 mLocked.pointerSprite->setIcon(mLocked.pointerIcon);
             } else {
-                std::map<int, SpriteIcon>::const_iterator iter =
+                std::map<int32_t, SpriteIcon>::const_iterator iter =
                     mLocked.additionalMouseResources.find(mLocked.requestedPointerShape);
                 if (iter != mLocked.additionalMouseResources.end()) {
+                    std::map<int32_t, PointerAnimation>::const_iterator anim_iter =
+                            mLocked.animationResources.find(mLocked.requestedPointerShape);
+                    if (anim_iter != mLocked.animationResources.end()) {
+                        mLocked.animationFrameIndex = 0;
+                        mLocked.lastFrameUpdatedTime = systemTime(SYSTEM_TIME_MONOTONIC);
+                        startAnimationLocked();
+                    }
                     mLocked.pointerSprite->setIcon(iter->second);
                 } else {
                     ALOGW("Can't find the resource for icon id %d", mLocked.requestedPointerShape);
diff --git a/libs/input/PointerController.h b/libs/input/PointerController.h
index 6d840db..b6c01d2 100644
--- a/libs/input/PointerController.h
+++ b/libs/input/PointerController.h
@@ -20,6 +20,7 @@
 #include "SpriteController.h"
 
 #include <map>
+#include <vector>
 
 #include <ui/DisplayInfo.h>
 #include <input/Input.h>
@@ -30,8 +31,6 @@
 #include <utils/String8.h>
 #include <gui/DisplayEventReceiver.h>
 
-#include <SkBitmap.h>
-
 namespace android {
 
 /*
@@ -43,6 +42,11 @@
     SpriteIcon spotAnchor;
 };
 
+struct PointerAnimation {
+    std::vector<SpriteIcon> animationFrames;
+    nsecs_t durationPerFrame;
+};
+
 /*
  * Pointer controller policy interface.
  *
@@ -59,7 +63,8 @@
 
 public:
     virtual void loadPointerResources(PointerResources* outResources) = 0;
-    virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources) = 0;
+    virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
+            std::map<int32_t, PointerAnimation>* outAnimationResources) = 0;
     virtual int32_t getDefaultPointerIconId() = 0;
 };
 
@@ -98,7 +103,7 @@
             const uint32_t* spotIdToIndex, BitSet32 spotIdBits);
     virtual void clearSpots();
 
-    void updatePointerShape(int iconId);
+    void updatePointerShape(int32_t iconId);
     void setDisplayViewport(int32_t width, int32_t height, int32_t orientation);
     void setPointerIcon(const SpriteIcon& icon);
     void setInactivityTimeout(InactivityTimeout inactivityTimeout);
@@ -145,6 +150,9 @@
         bool animationPending;
         nsecs_t animationTime;
 
+        size_t animationFrameIndex;
+        nsecs_t lastFrameUpdatedTime;
+
         int32_t displayWidth;
         int32_t displayHeight;
         int32_t displayOrientation;
@@ -162,7 +170,8 @@
         SpriteIcon pointerIcon;
         bool pointerIconChanged;
 
-        std::map<int, SpriteIcon> additionalMouseResources;
+        std::map<int32_t, SpriteIcon> additionalMouseResources;
+        std::map<int32_t, PointerAnimation> animationResources;
 
         int32_t requestedPointerShape;
 
@@ -178,6 +187,8 @@
     void handleMessage(const Message& message);
     int handleEvent(int fd, int events, void* data);
     void doAnimate(nsecs_t timestamp);
+    bool doFadingAnimationLocked(nsecs_t timestamp);
+    bool doBitmapAnimationLocked(nsecs_t timestamp);
     void doInactivityTimeout();
 
     void startAnimationLocked();
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 6bf5721..445ee6f 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -17,6 +17,8 @@
 package android.media;
 
 import java.io.IOException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
 import java.util.Date;
@@ -128,6 +130,9 @@
     // use sLock to serialize the accesses.
     private static final Object sLock = new Object();
 
+    // Pattern to check non zero timestamp
+    private static final Pattern sNonZeroTimePattern = Pattern.compile(".*[1-9].*");
+
     /**
      * Reads Exif tags from the specified JPEG file.
      */
@@ -367,7 +372,8 @@
      */
     public long getDateTime() {
         String dateTimeString = mAttributes.get(TAG_DATETIME);
-        if (dateTimeString == null) return -1;
+        if (dateTimeString == null
+                || !sNonZeroTimePattern.matcher(dateTimeString).matches()) return -1;
 
         ParsePosition pos = new ParsePosition(0);
         try {
@@ -402,7 +408,9 @@
     public long getGpsDateTime() {
         String date = mAttributes.get(TAG_GPS_DATESTAMP);
         String time = mAttributes.get(TAG_GPS_TIMESTAMP);
-        if (date == null || time == null) return -1;
+        if (date == null || time == null
+                || (!sNonZeroTimePattern.matcher(date).matches()
+                && !sNonZeroTimePattern.matcher(time).matches())) return -1;
 
         String dateTimeString = date + ' ' + time;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 069279f..d3d9bef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -470,7 +470,6 @@
                         processForRemoteInput(sbn.getNotification());
                         String key = sbn.getKey();
                         boolean isUpdate = mNotificationData.get(key) != null;
-
                         // In case we don't allow child notifications, we ignore children of
                         // notifications that have a summary, since we're not going to show them
                         // anyway. This is true also when the summary is canceled,
@@ -2023,6 +2022,7 @@
         }
 
         Notification n = notification.getNotification();
+        mNotificationData.updateRanking(ranking);
 
         boolean applyInPlace = !entry.cacheContentViews(mContext, notification.getNotification());
         boolean shouldInterrupt = shouldInterrupt(entry, notification);
@@ -2077,7 +2077,6 @@
             inflateViews(entry, mStackScroller);
         }
         updateHeadsUp(key, entry, shouldInterrupt, alertAgain);
-        mNotificationData.updateRanking(ranking);
         updateNotifications();
 
         // Update the veto button accordingly (and as a result, whether this row is
@@ -2167,7 +2166,6 @@
         boolean accessibilityForcesLaunch = isFullscreen
                 && mAccessibilityManager.isTouchExplorationEnabled();
         boolean justLaunchedFullScreenIntent = entry.hasJustLaunchedFullScreenIntent();
-
         boolean interrupt = (isFullscreen || (isHighPriority && (isNoisy || hasTicker)))
                 && isAllowed
                 && !accessibilityForcesLaunch
@@ -2175,7 +2173,8 @@
                 && mPowerManager.isScreenOn()
                 && (!mStatusBarKeyguardViewManager.isShowing()
                         || mStatusBarKeyguardViewManager.isOccluded())
-                && !mStatusBarKeyguardViewManager.isInputRestricted();
+                && !mStatusBarKeyguardViewManager.isInputRestricted()
+                && !mNotificationData.shouldSuppressPeek(sbn.getKey());
         try {
             interrupt = interrupt && !mDreamManager.isDreaming();
         } catch (RemoteException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 6a90d8e..4328e24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -292,6 +292,15 @@
         return NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
     }
 
+    public boolean shouldSuppressPeek(String key) {
+        if (mRankingMap != null) {
+            mRankingMap.getRanking(key, mTmpRanking);
+            return (mTmpRanking.getSuppressedVisualEffects()
+                    & NotificationListenerService.SUPPRESSED_EFFECT_PEEK) != 0;
+        }
+        return false;
+    }
+
     private void updateRankingAndSort(RankingMap ranking) {
         if (ranking != null) {
             mRankingMap = ranking;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 9ab2a2c..0cddf1d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1261,6 +1261,7 @@
             Entry oldEntry) {
         if (DEBUG) Log.d(TAG, "addNotification key=" + notification.getKey());
 
+        mNotificationData.updateRanking(ranking);
         Entry shadeEntry = createNotificationViews(notification);
         if (shadeEntry == null) {
             return;
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index c228422..9eb66dd 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -88,6 +88,7 @@
     private SettingsObserver mSettingObserver;
 
     native static boolean vibratorExists();
+    native static void vibratorInit();
     native static void vibratorOn(long milliseconds);
     native static void vibratorOff();
 
@@ -195,6 +196,7 @@
     }
 
     VibratorService(Context context) {
+        vibratorInit();
         // Reset the hardware to a default state, in case this is a runtime
         // restart instead of a fresh boot.
         vibratorOff();
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 025126f..6e6bfb7 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -17969,7 +17969,7 @@
 
         app.systemNoUi = false;
 
-        final int PROCESS_STATE_TOP = mTopProcessState;
+        final int PROCESS_STATE_CUR_TOP = mTopProcessState;
 
         // Determine the importance of the process, starting with most
         // important to least, and assign an appropriate OOM adjustment.
@@ -17984,7 +17984,7 @@
             schedGroup = Process.THREAD_GROUP_DEFAULT;
             app.adjType = "top-activity";
             foregroundActivities = true;
-            procState = PROCESS_STATE_TOP;
+            procState = PROCESS_STATE_CUR_TOP;
         } else if (app.instrumentationClass != null) {
             // Don't want to kill running instrumentation.
             adj = ProcessList.FOREGROUND_APP_ADJ;
@@ -18038,8 +18038,8 @@
                         adj = ProcessList.VISIBLE_APP_ADJ;
                         app.adjType = "visible";
                     }
-                    if (procState > PROCESS_STATE_TOP) {
-                        procState = PROCESS_STATE_TOP;
+                    if (procState > PROCESS_STATE_CUR_TOP) {
+                        procState = PROCESS_STATE_CUR_TOP;
                     }
                     schedGroup = Process.THREAD_GROUP_DEFAULT;
                     app.cached = false;
@@ -18057,8 +18057,8 @@
                         adj = ProcessList.PERCEPTIBLE_APP_ADJ;
                         app.adjType = "pausing";
                     }
-                    if (procState > PROCESS_STATE_TOP) {
-                        procState = PROCESS_STATE_TOP;
+                    if (procState > PROCESS_STATE_CUR_TOP) {
+                        procState = PROCESS_STATE_CUR_TOP;
                     }
                     schedGroup = Process.THREAD_GROUP_DEFAULT;
                     app.cached = false;
@@ -18096,7 +18096,8 @@
             }
         }
 
-        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
+        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
+                || procState > ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE) {
             if (app.foregroundServices) {
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b84811f..fd1e9dd 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -17,6 +17,8 @@
 package com.android.server.notification;
 
 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS;
+import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_LIGHTS;
+import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_PEEK;
 import static android.service.notification.NotificationListenerService.TRIM_FULL;
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
@@ -78,7 +80,6 @@
 import android.os.Vibrator;
 import android.provider.Settings;
 import android.service.notification.Condition;
-import android.service.notification.IConditionListener;
 import android.service.notification.IConditionProvider;
 import android.service.notification.INotificationListener;
 import android.service.notification.IStatusBarNotificationHolder;
@@ -2511,7 +2512,9 @@
         // light
         // release the light
         boolean wasShowLights = mLights.remove(record.getKey());
-        if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold) {
+        if ((notification.flags & Notification.FLAG_SHOW_LIGHTS) != 0 && aboveThreshold
+                && ((record.getSuppressedVisualEffects()
+                & NotificationListenerService.SUPPRESSED_EFFECT_LIGHTS) == 0)) {
             mLights.add(record.getKey());
             updateLightsLocked();
             if (mUseAttentionLight) {
@@ -2701,6 +2704,11 @@
     // let zen mode evaluate this record
     private void applyZenModeLocked(NotificationRecord record) {
         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
+        if (record.isIntercepted()) {
+            int suppressed = (mZenModeHelper.shouldSuppressLight() ? SUPPRESSED_EFFECT_LIGHTS : 0)
+                    | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0);
+            record.setSuppressedVisualEffects(suppressed);
+        }
     }
 
     // lock on mNotificationList
@@ -3234,6 +3242,7 @@
         ArrayList<String> keys = new ArrayList<String>(N);
         ArrayList<String> interceptedKeys = new ArrayList<String>(N);
         Bundle visibilityOverrides = new Bundle();
+        Bundle suppressedVisualEffects = new Bundle();
         for (int i = 0; i < N; i++) {
             NotificationRecord record = mNotificationList.get(i);
             if (!isVisibleToListener(record.sbn, info)) {
@@ -3242,7 +3251,10 @@
             keys.add(record.sbn.getKey());
             if (record.isIntercepted()) {
                 interceptedKeys.add(record.sbn.getKey());
+
             }
+            suppressedVisualEffects.putInt(
+                    record.sbn.getKey(), record.getSuppressedVisualEffects());
             if (record.getPackageVisibilityOverride()
                     != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE) {
                 visibilityOverrides.putInt(record.sbn.getKey(),
@@ -3264,7 +3276,7 @@
         String[] keysAr = keys.toArray(new String[keys.size()]);
         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
-                speedBumpIndex);
+                speedBumpIndex, suppressedVisualEffects);
     }
 
     private boolean isVisibleToListener(StatusBarNotification sbn, ManagedServiceInfo listener) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index f37702c..2a7568d 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -83,6 +83,8 @@
     private String mGlobalSortKey;
     private int mPackageVisibility;
 
+    private int mSuppressedVisualEffects = 0;
+
     @VisibleForTesting
     public NotificationRecord(StatusBarNotification sbn, int score)
     {
@@ -199,6 +201,7 @@
         pw.println(prefix + "  mCreationTimeMs=" + mCreationTimeMs);
         pw.println(prefix + "  mVisibleSinceMs=" + mVisibleSinceMs);
         pw.println(prefix + "  mUpdateTimeMs=" + mUpdateTimeMs);
+        pw.println(prefix + "  mSuppressedVisualEffects= " + mSuppressedVisualEffects);
     }
 
 
@@ -274,6 +277,14 @@
         return mIntercept;
     }
 
+    public void setSuppressedVisualEffects(int effects) {
+        mSuppressedVisualEffects = effects;
+    }
+
+    public int getSuppressedVisualEffects() {
+        return mSuppressedVisualEffects;
+    }
+
     public boolean isCategory(String category) {
         return Objects.equals(getNotification().category, category);
     }
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index a1f8c41..dbdc3f4 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -138,6 +138,18 @@
         }
     }
 
+    public boolean shouldSuppressLight() {
+        synchronized (mConfig) {
+            return !mConfig.allowLights;
+        }
+    }
+
+    public boolean shouldSuppressPeek() {
+        synchronized (mConfig) {
+            return !mConfig.allowPeek;
+        }
+    }
+
     public void addCallback(Callback callback) {
         mCallbacks.add(callback);
     }
@@ -394,11 +406,11 @@
             return;
         }
         pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s,"
-                + "events=%s,reminders=%s)\n",
+                + "events=%s,reminders=%s,lights=%s,peek=%s)\n",
                 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
                 config.allowRepeatCallers, config.allowMessages,
                 ZenModeConfig.sourceToString(config.allowMessagesFrom),
-                config.allowEvents, config.allowReminders);
+                config.allowEvents, config.allowReminders, config.allowLights, config.allowPeek);
         pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
         if (config.automaticRules.isEmpty()) return;
         final int N = config.automaticRules.size();
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index e4dbf65..8fac9da 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -871,7 +871,7 @@
             return false;
         }
         PackageSetting sysPkg = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName);
-        if (sysPkg != null) {
+        if (sysPkg != null && sysPkg.pkg != null) {
             if ((sysPkg.pkg.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) == 0) {
                 return false;
             }
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index 64278ed..03fbd19 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -22,32 +22,69 @@
 
 #include <utils/misc.h>
 #include <utils/Log.h>
-#include <hardware_legacy/vibrator.h>
+#include <hardware/vibrator.h>
 
 #include <stdio.h>
 
 namespace android
 {
 
+static hw_module_t *gVibraModule = NULL;
+static vibrator_device_t *gVibraDevice = NULL;
+
+static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
+{
+    if (gVibraModule != NULL) {
+        return;
+    }
+
+    int err = hw_get_module(VIBRATOR_HARDWARE_MODULE_ID, (hw_module_t const**)&gVibraModule);
+
+    if (err) {
+        ALOGE("Couldn't load %s module (%s)", VIBRATOR_HARDWARE_MODULE_ID, strerror(-err));
+    } else {
+        if (gVibraModule) {
+            vibrator_open(gVibraModule, &gVibraDevice);
+        }
+    }
+}
+
 static jboolean vibratorExists(JNIEnv* /* env */, jobject /* clazz */)
 {
-    return vibrator_exists() > 0 ? JNI_TRUE : JNI_FALSE;
+    if (gVibraModule && gVibraDevice) {
+        return JNI_TRUE;
+    } else {
+        return JNI_FALSE;
+    }
 }
 
 static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
 {
-    // ALOGI("vibratorOn\n");
-    vibrator_on(timeout_ms);
+    if (gVibraDevice) {
+        int err = gVibraDevice->vibrator_on(gVibraDevice, timeout_ms);
+        if (err != 0) {
+            ALOGE("The hw module failed in vibrator_on: %s", strerror(-err));
+        }
+    } else {
+        ALOGW("Tried to vibrate but there is no vibrator device.");
+    }
 }
 
 static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
 {
-    // ALOGI("vibratorOff\n");
-    vibrator_off();
+    if (gVibraDevice) {
+        int err = gVibraDevice->vibrator_off(gVibraDevice);
+        if (err != 0) {
+            ALOGE("The hw module failed in vibrator_off(): %s", strerror(-err));
+        }
+    } else {
+        ALOGW("Tried to stop vibrating but there is no vibrator device.");
+    }
 }
 
 static const JNINativeMethod method_table[] = {
     { "vibratorExists", "()Z", (void*)vibratorExists },
+    { "vibratorInit", "()V", (void*)vibratorInit },
     { "vibratorOn", "(J)V", (void*)vibratorOn },
     { "vibratorOff", "()V", (void*)vibratorOff }
 };
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index be190cb..b5654ee 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -152,18 +152,23 @@
             getInputWindowHandleObjLocalRef(env);
 }
 
-static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t style,
-        SpriteIcon* outSpriteIcon) {
-    PointerIcon pointerIcon;
+static void loadSystemIconAsSpriteWithPointerIcon(JNIEnv* env, jobject contextObj, int32_t style,
+        PointerIcon* outPointerIcon, SpriteIcon* outSpriteIcon) {
     status_t status = android_view_PointerIcon_loadSystemIcon(env,
-            contextObj, style, &pointerIcon);
+            contextObj, style, outPointerIcon);
     if (!status) {
-        pointerIcon.bitmap.copyTo(&outSpriteIcon->bitmap, kN32_SkColorType);
-        outSpriteIcon->hotSpotX = pointerIcon.hotSpotX;
-        outSpriteIcon->hotSpotY = pointerIcon.hotSpotY;
+        outPointerIcon->bitmap.copyTo(&outSpriteIcon->bitmap, kN32_SkColorType);
+        outSpriteIcon->hotSpotX = outPointerIcon->hotSpotX;
+        outSpriteIcon->hotSpotY = outPointerIcon->hotSpotY;
     }
 }
 
+static void loadSystemIconAsSprite(JNIEnv* env, jobject contextObj, int32_t style,
+                                   SpriteIcon* outSpriteIcon) {
+    PointerIcon pointerIcon;
+    loadSystemIconAsSpriteWithPointerIcon(env, contextObj, style, &pointerIcon, outSpriteIcon);
+}
+
 enum {
     WM_ACTION_PASS_TO_USER = 1,
 };
@@ -238,7 +243,8 @@
     /* --- PointerControllerPolicyInterface implementation --- */
 
     virtual void loadPointerResources(PointerResources* outResources);
-    virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources);
+    virtual void loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
+            std::map<int32_t, PointerAnimation>* outAnimationResources);
     virtual int32_t getDefaultPointerIconId();
 
 private:
@@ -1041,14 +1047,31 @@
             &outResources->spotAnchor);
 }
 
-void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources) {
+void NativeInputManager::loadAdditionalMouseResources(std::map<int32_t, SpriteIcon>* outResources,
+        std::map<int32_t, PointerAnimation>* outAnimationResources) {
     JNIEnv* env = jniEnv();
 
     for (int iconId = POINTER_ICON_STYLE_CONTEXT_MENU; iconId <= POINTER_ICON_STYLE_GRABBING;
              ++iconId) {
-        loadSystemIconAsSprite(env, mContextObj, iconId, &((*outResources)[iconId]));
+        PointerIcon pointerIcon;
+        loadSystemIconAsSpriteWithPointerIcon(
+                env, mContextObj, iconId, &pointerIcon, &((*outResources)[iconId]));
+        if (!pointerIcon.bitmapFrames.empty()) {
+            PointerAnimation& animationData = (*outAnimationResources)[iconId];
+            size_t numFrames = pointerIcon.bitmapFrames.size() + 1;
+            animationData.durationPerFrame =
+                    milliseconds_to_nanoseconds(pointerIcon.durationPerFrame);
+            animationData.animationFrames.reserve(numFrames);
+            animationData.animationFrames.push_back(SpriteIcon(
+                    pointerIcon.bitmap, pointerIcon.hotSpotX, pointerIcon.hotSpotY));
+            for (size_t i = 0; i < numFrames - 1; ++i) {
+              animationData.animationFrames.push_back(SpriteIcon(
+                      pointerIcon.bitmapFrames[i], pointerIcon.hotSpotX, pointerIcon.hotSpotY));
+            }
+        }
     }
-    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_NULL, &((*outResources)[POINTER_ICON_STYLE_NULL]));
+    loadSystemIconAsSprite(env, mContextObj, POINTER_ICON_STYLE_NULL,
+            &((*outResources)[POINTER_ICON_STYLE_NULL]));
 }
 
 int32_t NativeInputManager::getDefaultPointerIconId() {
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index c743f24..31c3670 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -2436,6 +2436,8 @@
                 // Active device/profile owners must remain active admins.
                 if (isDeviceOwner(adminReceiver, userHandle)
                         || isProfileOwner(adminReceiver, userHandle)) {
+                    Slog.e(LOG_TAG, "Device/profile owner cannot be removed: component=" +
+                            adminReceiver);
                     return;
                 }
                 mContext.enforceCallingOrSelfPermission(
@@ -3184,7 +3186,8 @@
         if (!mHasFeature) {
             return false;
         }
-        final int userHandle = UserHandle.getCallingUserId();
+        final int callingUid = mInjector.binderGetCallingUid();
+        final int userHandle = mInjector.userHandleGetCallingUserId();
 
         long ident = mInjector.binderClearCallingIdentity();
         try {
@@ -3200,10 +3203,16 @@
 
         int quality;
         synchronized (this) {
-            // This api can only be called by an active device admin,
-            // so try to retrieve it to check that the caller is one.
-            final ActiveAdmin admin = getActiveAdminForCallerLocked(null,
-                    DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
+            // If caller has PO (or DO), it can clear the password, so see if that's the case
+            // first.
+            ActiveAdmin admin = getActiveAdminWithPolicyForUidLocked(
+                    null, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, callingUid);
+            if (admin == null) {
+                // Otherwise, make sure the caller has any active admin with the right policy.
+                admin = getActiveAdminForCallerLocked(null,
+                        DeviceAdminInfo.USES_POLICY_RESET_PASSWORD);
+            }
+
             final ComponentName adminComponent = admin.info.getComponent();
 
             // As of N, only profile owners and device owners can reset the password.
@@ -3316,7 +3325,6 @@
             }
         }
 
-        int callingUid = mInjector.binderGetCallingUid();
         DevicePolicyData policy = getUserData(userHandle);
         if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
             Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user");
diff --git a/tests/RenderScriptTests/Fountain/Android.mk b/tests/RenderScriptTests/Fountain/Android.mk
deleted file mode 100644
index 0517aef..0000000
--- a/tests/RenderScriptTests/Fountain/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-LOCAL_SDK_VERSION := 17
-
-LOCAL_PACKAGE_NAME := RsFountain
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/Fountain/AndroidManifest.xml b/tests/RenderScriptTests/Fountain/AndroidManifest.xml
deleted file mode 100644
index d19b8c3..0000000
--- a/tests/RenderScriptTests/Fountain/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.rs.fountain">
-    <uses-sdk android:minSdkVersion="14" />
-    <application
-        android:label="RsFountain"
-        android:hardwareAccelerated="true"
-        android:icon="@drawable/test_pattern">
-        <activity android:name="Fountain">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/Fountain/_index.html b/tests/RenderScriptTests/Fountain/_index.html
deleted file mode 100644
index 223242f..0000000
--- a/tests/RenderScriptTests/Fountain/_index.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<p>An example that renders many dots on the screen that follow a user's touch. The dots fall 
-to the bottom of the screen when the user releases the finger.</p>
-
-
-
diff --git a/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png b/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/Fountain/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java
deleted file mode 100644
index 311455a..0000000
--- a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/Fountain.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.fountain;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-
-import java.lang.Runtime;
-
-public class Fountain extends Activity {
-    //EventListener mListener = new EventListener();
-
-    private static final String LOG_TAG = "libRS_jni";
-    private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = false;
-
-    private FountainView mView;
-
-    // get the current looper (from your Activity UI thread for instance
-
-
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new FountainView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        Log.e("rs", "onResume");
-
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        Log.e("rs", "onPause");
-
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onPause();
-        mView.pause();
-
-
-
-        //Runtime.getRuntime().exit(0);
-    }
-
-
-    static void log(String message) {
-        if (LOG_ENABLED) {
-            Log.v(LOG_TAG, message);
-        }
-    }
-
-
-}
-
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java
deleted file mode 100644
index 646c807..0000000
--- a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainRS.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.fountain;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-
-public class FountainRS {
-    public static final int PART_COUNT = 50000;
-
-    public FountainRS() {
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private ScriptC_fountain mScript;
-    public void init(RenderScriptGL rs, Resources res) {
-        mRS = rs;
-        mRes = res;
-
-        ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
-        pfb.setVaryingColor(true);
-        rs.bindProgramFragment(pfb.create());
-
-        ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);//
- //                                                        Allocation.USAGE_GRAPHICS_VERTEX);
-
-        Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
-        smb.addVertexAllocation(points.getAllocation());
-        smb.addIndexSetType(Mesh.Primitive.POINT);
-        Mesh sm = smb.create();
-
-        mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain);
-        mScript.set_partMesh(sm);
-        mScript.bind_point(points);
-        mRS.bindRootScript(mScript);
-    }
-
-    boolean holdingColor[] = new boolean[10];
-    public void newTouchPosition(float x, float y, float pressure, int id) {
-        if (id >= holdingColor.length) {
-            return;
-        }
-        int rate = (int)(pressure * pressure * 500.f);
-        if (rate > 500) {
-            rate = 500;
-        }
-        if (rate > 0) {
-            mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]);
-            holdingColor[id] = true;
-        } else {
-            holdingColor[id] = false;
-        }
-
-    }
-}
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java
deleted file mode 100644
index 98cec55..0000000
--- a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/FountainView.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.fountain;
-
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-public class FountainView extends RSSurfaceView {
-
-    public FountainView(Context context) {
-        super(context);
-        //setFocusable(true);
-    }
-
-    private RenderScriptGL mRS;
-    private FountainRS mRender;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new FountainRS();
-            mRender.init(mRS, getResources());
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        int act = ev.getActionMasked();
-        if (act == ev.ACTION_UP) {
-            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
-            return false;
-        } else if (act == MotionEvent.ACTION_POINTER_UP) {
-            // only one pointer going up, we can get the index like this
-            int pointerIndex = ev.getActionIndex();
-            int pointerId = ev.getPointerId(pointerIndex);
-            mRender.newTouchPosition(0, 0, 0, pointerId);
-        }
-        int count = ev.getHistorySize();
-        int pcount = ev.getPointerCount();
-
-        for (int p=0; p < pcount; p++) {
-            int id = ev.getPointerId(p);
-            mRender.newTouchPosition(ev.getX(p),
-                                     ev.getY(p),
-                                     ev.getPressure(p),
-                                     id);
-
-            for (int i=0; i < count; i++) {
-                mRender.newTouchPosition(ev.getHistoricalX(p, i),
-                                         ev.getHistoricalY(p, i),
-                                         ev.getHistoricalPressure(p, i),
-                                         id);
-            }
-        }
-        return true;
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs b/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs
deleted file mode 100644
index 151b689..0000000
--- a/tests/RenderScriptTests/Fountain/src/com/example/android/rs/fountain/fountain.rs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Fountain test script
-#pragma version(1)
-#pragma rs_fp_relaxed
-
-#pragma rs java_package_name(com.example.android.rs.fountain)
-
-#pragma stateFragment(parent)
-
-#include "rs_graphics.rsh"
-
-static int newPart = 0;
-rs_mesh partMesh;
-
-typedef struct __attribute__((packed, aligned(4))) Point {
-    float2 delta;
-    float2 position;
-    uchar4 color;
-} Point_t;
-Point_t *point;
-
-int root() {
-    float dt = min(rsGetDt(), 0.1f);
-    rsgClearColor(0.f, 0.f, 0.f, 1.f);
-    const float height = rsgGetHeight();
-    const int size = rsAllocationGetDimX(rsGetAllocation(point));
-    float dy2 = dt * (10.f);
-    Point_t * p = point;
-    for (int ct=0; ct < size; ct++) {
-        p->delta.y += dy2;
-        p->position += p->delta;
-        if ((p->position.y > height) && (p->delta.y > 0)) {
-            p->delta.y *= -0.3f;
-        }
-        p++;
-    }
-
-    rsgDrawMesh(partMesh);
-    return 1;
-}
-
-static float4 partColor[10];
-void addParticles(int rate, float x, float y, int index, bool newColor)
-{
-    if (newColor) {
-        partColor[index].x = rsRand(0.5f, 1.0f);
-        partColor[index].y = rsRand(1.0f);
-        partColor[index].z = rsRand(1.0f);
-    }
-    float rMax = ((float)rate) * 0.02f;
-    int size = rsAllocationGetDimX(rsGetAllocation(point));
-    uchar4 c = rsPackColorTo8888(partColor[index]);
-
-    Point_t * np = &point[newPart];
-    float2 p = {x, y};
-    while (rate--) {
-        float angle = rsRand(3.14f * 2.f);
-        float len = rsRand(rMax);
-        np->delta.x = len * sin(angle);
-        np->delta.y = len * cos(angle);
-        np->position = p;
-        np->color = c;
-        newPart++;
-        np++;
-        if (newPart >= size) {
-            newPart = 0;
-            np = &point[newPart];
-        }
-    }
-}
-
diff --git a/tests/RenderScriptTests/FountainFbo/Android.mk b/tests/RenderScriptTests/FountainFbo/Android.mk
deleted file mode 100644
index c0f3323..0000000
--- a/tests/RenderScriptTests/FountainFbo/Android.mk
+++ /dev/null
@@ -1,30 +0,0 @@
-#
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-
-# TODO: build fails with this set
-# LOCAL_SDK_VERSION := current
-
-LOCAL_PACKAGE_NAME := RsFountainFbo
-LOCAL_SDK_VERSION := 14
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml b/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml
deleted file mode 100644
index 082744b..0000000
--- a/tests/RenderScriptTests/FountainFbo/AndroidManifest.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.example.android.rs.fountainfbo">
-    <uses-sdk android:minSdkVersion="14" />
-    <application
-        android:label="RsFountainFbo"
-        android:hardwareAccelerated="true"
-        android:icon="@drawable/test_pattern">
-        <activity android:name="FountainFbo">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/FountainFbo/_index.html b/tests/RenderScriptTests/FountainFbo/_index.html
deleted file mode 100644
index 5508657..0000000
--- a/tests/RenderScriptTests/FountainFbo/_index.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<p>An example that renders many dots on the screen that follow a user's touch. The dots fall 
-to the bottom of the screen when no touch is detected. This example modifies
-the <a href="../Fountain/index.html">Fountain</a> sample to include rendering to a
-a framebuffer object as well as the default framebuffer.</p>
-
-
-
diff --git a/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png b/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/FountainFbo/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java
deleted file mode 100644
index d8ba30f..0000000
--- a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFbo.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.fountainfbo;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-
-public class FountainFbo extends Activity {
-    private static final String LOG_TAG = "libRS_jni";
-    private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = false;
-
-    private FountainFboView mView;
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        /* Create our Preview view and set it as the content of our Activity */
-        mView = new FountainFboView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        Log.e("rs", "onResume");
-
-        /* Ideally a game should implement onResume() and onPause()
-         to take appropriate action when the activity loses focus */
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        Log.e("rs", "onPause");
-
-        /* Ideally a game should implement onResume() and onPause()
-        to take appropriate action when the activity loses focus */
-        super.onPause();
-        mView.pause();
-    }
-
-    static void log(String message) {
-        if (LOG_ENABLED) {
-            Log.v(LOG_TAG, message);
-        }
-    }
-}
-
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java
deleted file mode 100644
index 3bf3ff1..0000000
--- a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboRS.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.fountainfbo;
-
-import android.content.res.Resources;
-import android.renderscript.Allocation;
-import android.renderscript.Element;
-import android.renderscript.Mesh;
-import android.renderscript.ProgramFragment;
-import android.renderscript.ProgramFragmentFixedFunction;
-import android.renderscript.RenderScriptGL;
-import android.renderscript.Type;
-
-public class FountainFboRS {
-    public static final int PART_COUNT = 50000;
-
-    public FountainFboRS() {
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private ScriptC_fountainfbo mScript;
-    private Allocation mColorBuffer;
-    private ProgramFragment mProgramFragment;
-    private ProgramFragment mTextureProgramFragment;
-    public void init(RenderScriptGL rs, Resources res) {
-      mRS = rs;
-      mRes = res;
-
-      ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);
-
-      Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
-      smb.addVertexAllocation(points.getAllocation());
-      smb.addIndexSetType(Mesh.Primitive.POINT);
-      Mesh sm = smb.create();
-
-      mScript = new ScriptC_fountainfbo(mRS, mRes, R.raw.fountainfbo);
-      mScript.set_partMesh(sm);
-      mScript.bind_point(points);
-
-      ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
-      pfb.setVaryingColor(true);
-      mProgramFragment = pfb.create();
-      mScript.set_gProgramFragment(mProgramFragment);
-
-      /* Second fragment shader to use a texture (framebuffer object) to draw with */
-      pfb.setTexture(ProgramFragmentFixedFunction.Builder.EnvMode.REPLACE,
-          ProgramFragmentFixedFunction.Builder.Format.RGBA, 0);
-
-      /* Set the fragment shader in the Renderscript runtime */
-      mTextureProgramFragment = pfb.create();
-      mScript.set_gTextureProgramFragment(mTextureProgramFragment);
-
-      /* Create the allocation for the color buffer */
-      Type.Builder colorBuilder = new Type.Builder(mRS, Element.RGBA_8888(mRS));
-      colorBuilder.setX(256).setY(256);
-      mColorBuffer = Allocation.createTyped(mRS, colorBuilder.create(),
-      Allocation.USAGE_GRAPHICS_TEXTURE |
-      Allocation.USAGE_GRAPHICS_RENDER_TARGET);
-
-      /* Set the allocation in the Renderscript runtime */
-      mScript.set_gColorBuffer(mColorBuffer);
-
-      mRS.bindRootScript(mScript);
-  }
-
-    boolean holdingColor[] = new boolean[10];
-    public void newTouchPosition(float x, float y, float pressure, int id) {
-        if (id >= holdingColor.length) {
-            return;
-        }
-        int rate = (int)(pressure * pressure * 500.f);
-        if (rate > 500) {
-            rate = 500;
-        }
-        if (rate > 0) {
-            mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]);
-            holdingColor[id] = true;
-        } else {
-            holdingColor[id] = false;
-        }
-
-    }
-}
-
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java
deleted file mode 100644
index 8636717..0000000
--- a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/FountainFboView.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.example.android.rs.fountainfbo;
-
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScriptGL;
-import android.content.Context;
-import android.view.SurfaceHolder;
-import android.view.MotionEvent;
-
-public class FountainFboView extends RSSurfaceView {
-
-    public FountainFboView(Context context) {
-        super(context);
-    }
-
-    private RenderScriptGL mRS;
-    private FountainFboRS mRender;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new FountainFboRS();
-            mRender.init(mRS, getResources());
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        android.util.Log.e("rs", "onDetachedFromWindow");
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        int act = ev.getActionMasked();
-        if (act == ev.ACTION_UP) {
-            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
-            return false;
-        } else if (act == MotionEvent.ACTION_POINTER_UP) {
-            // only one pointer going up, we can get the index like this
-            int pointerIndex = ev.getActionIndex();
-            int pointerId = ev.getPointerId(pointerIndex);
-            mRender.newTouchPosition(0, 0, 0, pointerId);
-        }
-        int count = ev.getHistorySize();
-        int pcount = ev.getPointerCount();
-
-        for (int p=0; p < pcount; p++) {
-            int id = ev.getPointerId(p);
-            mRender.newTouchPosition(ev.getX(p),
-                                     ev.getY(p),
-                                     ev.getPressure(p),
-                                     id);
-
-            for (int i=0; i < count; i++) {
-                mRender.newTouchPosition(ev.getHistoricalX(p, i),
-                                         ev.getHistoricalY(p, i),
-                                         ev.getHistoricalPressure(p, i),
-                                         id);
-            }
-        }
-        return true;
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs b/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs
deleted file mode 100644
index 763f6ba..0000000
--- a/tests/RenderScriptTests/FountainFbo/src/com/example/android/rs/fountainfbo/fountainfbo.rs
+++ /dev/null
@@ -1,106 +0,0 @@
-// Fountain test script
-#pragma version(1)
-
-#pragma rs java_package_name(com.example.android.rs.fountainfbo)
-
-#pragma stateFragment(parent)
-
-#include "rs_graphics.rsh"
-
-static int newPart = 0;
-rs_mesh partMesh;
-rs_program_vertex gProgramVertex;
-
-//allocation for color buffer
-rs_allocation gColorBuffer;
-//fragment shader for rendering without a texture (used for rendering to framebuffer object)
-rs_program_fragment gProgramFragment;
-//fragment shader for rendering with a texture (used for rendering to default framebuffer)
-rs_program_fragment gTextureProgramFragment;
-
-typedef struct __attribute__((packed, aligned(4))) Point {
-    float2 delta;
-    float2 position;
-    uchar4 color;
-} Point_t;
-Point_t *point;
-
-int root() {
-    float dt = min(rsGetDt(), 0.1f);
-    rsgClearColor(0.f, 0.f, 0.f, 1.f);
-    const float height = rsgGetHeight();
-    const int size = rsAllocationGetDimX(rsGetAllocation(point));
-    float dy2 = dt * (10.f);
-    Point_t * p = point;
-    for (int ct=0; ct < size; ct++) {
-        p->delta.y += dy2;
-        p->position += p->delta;
-        if ((p->position.y > height) && (p->delta.y > 0)) {
-            p->delta.y *= -0.3f;
-        }
-        p++;
-    }
-    //Tell Renderscript runtime to render to the frame buffer object
-    rsgBindColorTarget(gColorBuffer, 0);
-
-    //Begin rendering on a white background
-    rsgClearColor(1.f, 1.f, 1.f, 1.f);
-    rsgDrawMesh(partMesh);
-
-    //When done, tell Renderscript runtime to stop rendering to framebuffer object
-    rsgClearAllRenderTargets();
-
-    //Bind a new fragment shader that declares the framebuffer object to be used as a texture
-    rsgBindProgramFragment(gTextureProgramFragment);
-
-    //Bind the framebuffer object to the fragment shader at slot 0 as a texture
-    rsgBindTexture(gTextureProgramFragment, 0, gColorBuffer);
-
-    //Draw a quad using the framebuffer object as the texture
-    float startX = 10, startY = 10;
-    float s = 256;
-    rsgDrawQuadTexCoords(startX, startY, 0, 0, 1,
-                         startX, startY + s, 0, 0, 0,
-                         startX + s, startY + s, 0, 1, 0,
-                         startX + s, startY, 0, 1, 1);
-
-    //Rebind the original fragment shader to render as normal
-    rsgBindProgramFragment(gProgramFragment);
-
-    //Render the main scene
-    rsgDrawMesh(partMesh);
-
-    return 1;
-}
-
-static float4 partColor[10];
-void addParticles(int rate, float x, float y, int index, bool newColor)
-{
-    if (newColor) {
-        partColor[index].x = rsRand(0.5f, 1.0f);
-        partColor[index].y = rsRand(1.0f);
-        partColor[index].z = rsRand(1.0f);
-    }
-    float rMax = ((float)rate) * 0.02f;
-    int size = rsAllocationGetDimX(rsGetAllocation(point));
-    uchar4 c = rsPackColorTo8888(partColor[index]);
-
-    Point_t * np = &point[newPart];
-    float2 p = {x, y};
-    while (rate--) {
-        float angle = rsRand(3.14f * 2.f);
-        float len = rsRand(rMax);
-        np->delta.x = len * sin(angle);
-        np->delta.y = len * cos(angle);
-        np->position = p;
-        np->color = c;
-        newPart++;
-        np++;
-        if (newPart >= size) {
-            newPart = 0;
-            np = &point[newPart];
-        }
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/Fountain_v11/Android.mk b/tests/RenderScriptTests/Fountain_v11/Android.mk
deleted file mode 100644
index ac2690c..0000000
--- a/tests/RenderScriptTests/Fountain_v11/Android.mk
+++ /dev/null
@@ -1,28 +0,0 @@
-#
-# Copyright (C) 2008 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
-#LOCAL_STATIC_JAVA_LIBRARIES := android.renderscript
-
-LOCAL_PACKAGE_NAME := Fountain_v11
-LOCAL_SDK_VERSION := 11
-
-include $(BUILD_PACKAGE)
diff --git a/tests/RenderScriptTests/Fountain_v11/AndroidManifest.xml b/tests/RenderScriptTests/Fountain_v11/AndroidManifest.xml
deleted file mode 100644
index fcb4faf..0000000
--- a/tests/RenderScriptTests/Fountain_v11/AndroidManifest.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.fountain_v11">
-    <uses-sdk android:minSdkVersion="11" />
-    <application 
-        android:label="Fountain_v11"
-        android:icon="@drawable/test_pattern">
-        <activity android:name="Fountain_v11">
-            <intent-filter>
-                <action android:name="android.intent.action.MAIN" />
-                <category android:name="android.intent.category.LAUNCHER" />
-            </intent-filter>
-        </activity>
-    </application>
-</manifest>
diff --git a/tests/RenderScriptTests/Fountain_v11/_index.html b/tests/RenderScriptTests/Fountain_v11/_index.html
deleted file mode 100644
index 223242f..0000000
--- a/tests/RenderScriptTests/Fountain_v11/_index.html
+++ /dev/null
@@ -1,5 +0,0 @@
-<p>An example that renders many dots on the screen that follow a user's touch. The dots fall 
-to the bottom of the screen when the user releases the finger.</p>
-
-
-
diff --git a/tests/RenderScriptTests/Fountain_v11/res/drawable/test_pattern.png b/tests/RenderScriptTests/Fountain_v11/res/drawable/test_pattern.png
deleted file mode 100644
index e7d1455..0000000
--- a/tests/RenderScriptTests/Fountain_v11/res/drawable/test_pattern.png
+++ /dev/null
Binary files differ
diff --git a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainRS.java b/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainRS.java
deleted file mode 100644
index e858100..0000000
--- a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainRS.java
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fountain_v11;
-
-import android.content.res.Resources;
-import android.renderscript.*;
-import android.util.Log;
-
-
-public class FountainRS {
-    public static final int PART_COUNT = 50000;
-
-    public FountainRS() {
-    }
-
-    private Resources mRes;
-    private RenderScriptGL mRS;
-    private ScriptC_fountain mScript;
-    public void init(RenderScriptGL rs, Resources res, int width, int height) {
-        mRS = rs;
-        mRes = res;
-
-        ProgramFragmentFixedFunction.Builder pfb = new ProgramFragmentFixedFunction.Builder(rs);
-        pfb.setVaryingColor(true);
-        rs.bindProgramFragment(pfb.create());
-
-        ScriptField_Point points = new ScriptField_Point(mRS, PART_COUNT);//
- //                                                        Allocation.USAGE_GRAPHICS_VERTEX);
-
-        Mesh.AllocationBuilder smb = new Mesh.AllocationBuilder(mRS);
-        smb.addVertexAllocation(points.getAllocation());
-        smb.addIndexSetType(Mesh.Primitive.POINT);
-        Mesh sm = smb.create();
-
-        mScript = new ScriptC_fountain(mRS, mRes, R.raw.fountain);
-        mScript.set_partMesh(sm);
-        mScript.bind_point(points);
-        mRS.bindRootScript(mScript);
-    }
-
-    boolean holdingColor[] = new boolean[10];
-    public void newTouchPosition(float x, float y, float pressure, int id) {
-        if (id >= holdingColor.length) {
-            return;
-        }
-        int rate = (int)(pressure * pressure * 500.f);
-        if (rate > 500) {
-            rate = 500;
-        }
-        if (rate > 0) {
-            mScript.invoke_addParticles(rate, x, y, id, !holdingColor[id]);
-            holdingColor[id] = true;
-        } else {
-            holdingColor[id] = false;
-        }
-
-    }
-}
diff --git a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainView.java b/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainView.java
deleted file mode 100644
index e82376c..0000000
--- a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/FountainView.java
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fountain_v11;
-
-import java.io.Writer;
-import java.util.ArrayList;
-import java.util.concurrent.Semaphore;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-import android.renderscript.RenderScriptGL;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.Bitmap;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
-import android.os.Handler;
-import android.os.Message;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-
-public class FountainView extends RSSurfaceView {
-
-    public FountainView(Context context) {
-        super(context);
-        //setFocusable(true);
-    }
-
-    private RenderScriptGL mRS;
-    private FountainRS mRender;
-
-    public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
-        super.surfaceChanged(holder, format, w, h);
-        if (mRS == null) {
-            RenderScriptGL.SurfaceConfig sc = new RenderScriptGL.SurfaceConfig();
-            mRS = createRenderScriptGL(sc);
-            mRS.setSurface(holder, w, h);
-            mRender = new FountainRS();
-            mRender.init(mRS, getResources(), w, h);
-        }
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        if (mRS != null) {
-            mRS = null;
-            destroyRenderScriptGL();
-        }
-    }
-
-
-    @Override
-    public boolean onTouchEvent(MotionEvent ev)
-    {
-        int act = ev.getActionMasked();
-        if (act == ev.ACTION_UP) {
-            mRender.newTouchPosition(0, 0, 0, ev.getPointerId(0));
-            return false;
-        } else if (act == MotionEvent.ACTION_POINTER_UP) {
-            // only one pointer going up, we can get the index like this
-            int pointerIndex = ev.getActionIndex();
-            int pointerId = ev.getPointerId(pointerIndex);
-            mRender.newTouchPosition(0, 0, 0, pointerId);
-        }
-        int count = ev.getHistorySize();
-        int pcount = ev.getPointerCount();
-
-        for (int p=0; p < pcount; p++) {
-            int id = ev.getPointerId(p);
-            mRender.newTouchPosition(ev.getX(p),
-                                     ev.getY(p),
-                                     ev.getPressure(p),
-                                     id);
-
-            for (int i=0; i < count; i++) {
-                mRender.newTouchPosition(ev.getHistoricalX(p, i),
-                                         ev.getHistoricalY(p, i),
-                                         ev.getHistoricalPressure(p, i),
-                                         id);
-            }
-        }
-        return true;
-    }
-}
-
-
diff --git a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/Fountain_v11.java b/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/Fountain_v11.java
deleted file mode 100644
index 2c07b27..0000000
--- a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/Fountain_v11.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.fountain_v11;
-
-import android.renderscript.RSSurfaceView;
-import android.renderscript.RenderScript;
-
-import android.app.Activity;
-import android.content.res.Configuration;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
-import android.provider.Settings.System;
-import android.util.Config;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-import android.view.View;
-import android.view.Window;
-import android.widget.Button;
-import android.widget.ListView;
-
-import java.lang.Runtime;
-
-public class Fountain_v11 extends Activity {
-    //EventListener mListener = new EventListener();
-
-    private static final String LOG_TAG = "libRS_jni";
-    private static final boolean DEBUG  = false;
-    private static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV;
-
-    private FountainView mView;
-
-    // get the current looper (from your Activity UI thread for instance
-
-
-
-    @Override
-    public void onCreate(Bundle icicle) {
-        super.onCreate(icicle);
-
-        // Create our Preview view and set it as the content of our
-        // Activity
-        mView = new FountainView(this);
-        setContentView(mView);
-    }
-
-    @Override
-    protected void onResume() {
-        Log.e("rs", "onResume");
-
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onResume();
-        mView.resume();
-    }
-
-    @Override
-    protected void onPause() {
-        Log.e("rs", "onPause");
-
-        // Ideally a game should implement onResume() and onPause()
-        // to take appropriate action when the activity looses focus
-        super.onPause();
-        mView.pause();
-
-
-
-        //Runtime.getRuntime().exit(0);
-    }
-
-
-    static void log(String message) {
-        if (LOG_ENABLED) {
-            Log.v(LOG_TAG, message);
-        }
-    }
-
-
-}
-
diff --git a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/fountain.rs b/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/fountain.rs
deleted file mode 100644
index 3b6c89a..0000000
--- a/tests/RenderScriptTests/Fountain_v11/src/com/android/fountain/fountain.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-// Fountain test script
-#pragma version(1)
-
-#pragma rs java_package_name(com.android.fountain_v11)
-
-#pragma stateFragment(parent)
-
-#include "rs_graphics.rsh"
-
-static int newPart = 0;
-rs_mesh partMesh;
-
-typedef struct __attribute__((packed, aligned(4))) Point {
-    float2 delta;
-    float2 position;
-    uchar4 color;
-} Point_t;
-Point_t *point;
-
-int root() {
-    float dt = min(rsGetDt(), 0.1f);
-    rsgClearColor(0.f, 0.f, 0.f, 1.f);
-    const float height = rsgGetHeight();
-    const int size = rsAllocationGetDimX(rsGetAllocation(point));
-    float dy2 = dt * (10.f);
-    Point_t * p = point;
-    for (int ct=0; ct < size; ct++) {
-        p->delta.y += dy2;
-        p->position += p->delta;
-        if ((p->position.y > height) && (p->delta.y > 0)) {
-            p->delta.y *= -0.3f;
-        }
-        p++;
-    }
-
-    rsgDrawMesh(partMesh);
-    return 1;
-}
-
-static float4 partColor[10];
-void addParticles(int rate, float x, float y, int index, bool newColor)
-{
-    if (newColor) {
-        partColor[index].x = rsRand(0.5f, 1.0f);
-        partColor[index].y = rsRand(1.0f);
-        partColor[index].z = rsRand(1.0f);
-    }
-    float rMax = ((float)rate) * 0.02f;
-    int size = rsAllocationGetDimX(rsGetAllocation(point));
-    uchar4 c = rsPackColorTo8888(partColor[index]);
-
-    Point_t * np = &point[newPart];
-    float2 p = {x, y};
-    while (rate--) {
-        float angle = rsRand(3.14f * 2.f);
-        float len = rsRand(rMax);
-        np->delta.x = len * sin(angle);
-        np->delta.y = len * cos(angle);
-        np->position = p;
-        np->color = c;
-        newPart++;
-        np++;
-        if (newPart >= size) {
-            newPart = 0;
-            np = &point[newPart];
-        }
-    }
-}
-
diff --git a/tools/layoutlib/.idea/encodings.xml b/tools/layoutlib/.idea/encodings.xml
index e206d70..f758959 100644
--- a/tools/layoutlib/.idea/encodings.xml
+++ b/tools/layoutlib/.idea/encodings.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <project version="4">
-  <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
-</project>
-
+  <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false">
+    <file url="PROJECT" charset="UTF-8" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
index b67afeb..cdcf0ea 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
@@ -76,19 +76,18 @@
             Class[] constructorParams = {View.class};
             Object[] constructorArgs = {getDecorContent()};
             LayoutlibCallback callback = params.getLayoutlibCallback();
-            // First try to load the class as was available before appcompat v23.1.1, without
-            // logging warnings.
+
+            // Check if the old action bar class is present.
+            String actionBarClass = WINDOW_ACTION_BAR_CLASS;
             try {
-                mWindowDecorActionBar = callback.loadClass(WINDOW_ACTION_BAR_CLASS,
-                        constructorParams, constructorArgs);
-            } catch (ClassNotFoundException ignore) {
-            }
-            if (mWindowDecorActionBar == null) {
-                // If failed, load the new class, while logging warnings.
-                mWindowDecorActionBar = callback.loadView(WINDOW_ACTION_BAR_CLASS_NEW,
-                        constructorParams, constructorArgs);
+                callback.findClass(actionBarClass);
+            } catch (ClassNotFoundException expected) {
+                // Failed to find the old class, use the newer one.
+                actionBarClass = WINDOW_ACTION_BAR_CLASS_NEW;
             }
 
+            mWindowDecorActionBar = callback.loadView(actionBarClass,
+                    constructorParams, constructorArgs);
             mWindowActionBarClass = mWindowDecorActionBar == null ? null :
                     mWindowDecorActionBar.getClass();
             setupActionBar();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 42e55e2..a6e5fb8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -33,7 +33,6 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap_Delegate;
@@ -228,18 +227,16 @@
      * Find the background color for this bar from the theme attributes. Only relevant to StatusBar
      * and NavigationBar.
      * <p/>
-     * Returns null if not found.
+     * Returns 0 if not found.
      *
      * @param colorAttrName the attribute name for the background color
      * @param translucentAttrName the attribute name for the translucency property of the bar.
      *
      * @throws NumberFormatException if color resolved to an invalid string.
      */
-    @Nullable
-    protected Integer getBarColor(@NonNull String colorAttrName,
-            @NonNull String translucentAttrName) {
+    protected int getBarColor(@NonNull String colorAttrName, @NonNull String translucentAttrName) {
         if (!Config.isGreaterOrEqual(mSimulatedPlatformVersion, LOLLIPOP)) {
-            return null;
+            return 0;
         }
         RenderResources renderResources = getContext().getRenderResources();
         // First check if the bar is translucent.
@@ -254,11 +251,10 @@
         if (transparent) {
             return getColor(renderResources, colorAttrName);
         }
-        return null;
+        return 0;
     }
 
-    @Nullable
-    private static Integer getColor(RenderResources renderResources, String attr) {
+    private static int getColor(RenderResources renderResources, String attr) {
         // From ?attr/foo to @color/bar. This is most likely an ItemResourceValue.
         ResourceValue resource = renderResources.findItemInTheme(attr, true);
         // Form @color/bar to the #AARRGGBB
@@ -279,7 +275,7 @@
                 }
             }
         }
-        return null;
+        return 0;
     }
 
     private ResourceValue getResourceValue(String reference) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index d50ce23..9c89bfe 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -65,8 +65,8 @@
         super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
                 "navigation_bar.xml", simulatedPlatformVersion);
 
-        Integer color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
-        setBackgroundColor(color == null ? 0xFF000000 : color);
+        int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
+        setBackgroundColor(color == 0 ? 0xFF000000 : color);
 
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index 95a5a58..2dc7c65 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -71,9 +71,8 @@
         // FIXME: use FILL_H?
         setGravity(Gravity.START | Gravity.TOP | Gravity.RIGHT);
 
-        Integer color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
-        setBackgroundColor(
-                color == null ? Config.getStatusBarColor(simulatedPlatformVersion) : color);
+        int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
+        setBackgroundColor(color == 0 ? Config.getStatusBarColor(simulatedPlatformVersion) : color);
 
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 2a4f583..0ffa357 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -421,7 +421,8 @@
                     gc.setComposite(AlphaComposite.Src);
 
                     gc.setColor(new Color(0x00000000, true));
-                    gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
+                    gc.fillRect(0, 0,
+                            mMeasuredScreenWidth, mMeasuredScreenHeight);
 
                     // done
                     gc.dispose();