Merge "QS: Add content description to page indicator" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index eb129da..04e1005 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5901,7 +5901,7 @@
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
-    method public java.lang.String getOrganizationName(android.content.ComponentName);
+    method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -5976,7 +5976,7 @@
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
     method public void setOrganizationColor(android.content.ComponentName, int);
-    method public void setOrganizationName(android.content.ComponentName, java.lang.String);
+    method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
     method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -8615,6 +8615,7 @@
     field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
     field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
     field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+    field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
     field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
     field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
     field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
@@ -8709,6 +8710,7 @@
     field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
     field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
     field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
     field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
diff --git a/api/system-current.txt b/api/system-current.txt
index 5bfbc16..f284262 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6044,7 +6044,7 @@
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
-    method public java.lang.String getOrganizationName(android.content.ComponentName);
+    method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -6126,7 +6126,7 @@
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
     method public void setOrganizationColor(android.content.ComponentName, int);
-    method public void setOrganizationName(android.content.ComponentName, java.lang.String);
+    method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
     method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -8934,6 +8934,7 @@
     field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
     field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
     field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+    field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
     field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
     field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
     field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
diff --git a/api/test-current.txt b/api/test-current.txt
index 04fedb1..a19a120 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5905,7 +5905,7 @@
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
-    method public java.lang.String getOrganizationName(android.content.ComponentName);
+    method public java.lang.CharSequence getOrganizationName(android.content.ComponentName);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
     method public long getPasswordExpirationTimeout(android.content.ComponentName);
@@ -5980,7 +5980,7 @@
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
     method public void setOrganizationColor(android.content.ComponentName, int);
-    method public void setOrganizationName(android.content.ComponentName, java.lang.String);
+    method public void setOrganizationName(android.content.ComponentName, java.lang.CharSequence);
     method public java.lang.String[] setPackagesSuspended(android.content.ComponentName, java.lang.String[], boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -8622,6 +8622,7 @@
     field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
     field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
     field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+    field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
     field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
     field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
     field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
@@ -8716,6 +8717,7 @@
     field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
     field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
     field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
+    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
     field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d5d4ca7..cd6e572 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -532,7 +532,8 @@
             public WifiScanner createService(ContextImpl ctx) {
                 IBinder b = ServiceManager.getService(Context.WIFI_SCANNING_SERVICE);
                 IWifiScanner service = IWifiScanner.Stub.asInterface(b);
-                return new WifiScanner(ctx.getOuterContext(), service);
+                return new WifiScanner(ctx.getOuterContext(), service,
+                        ConnectivityThread.getInstanceLooper());
             }});
 
         registerService(Context.WIFI_RTT_SERVICE, RttManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 96757bb..a7bb348 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6050,11 +6050,13 @@
      * {@link android.app.KeyguardManager#createConfirmDeviceCredentialIntent}.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @param color The 32bit representation of the color to be used.
+     * @param color The 24bit (0xRRGGBB) representation of the color to be used.
      * @throws SecurityException if {@code admin} is not a profile owner.
      */
     public void setOrganizationColor(@NonNull ComponentName admin, int color) {
         try {
+            // always enforce alpha channel to have 100% opacity
+            color |= 0xFF000000;
             mService.setOrganizationColor(admin, color);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
@@ -6066,7 +6068,7 @@
      *
      * Sets the color used for customization.
      *
-     * @param color The 32bit representation of the color to be used.
+     * @param color The 24bit (0xRRGGBB) representation of the color to be used.
      * @param userId which user to set the color to.
      * @RequiresPermission(allOf = {
      *       Manifest.permission.MANAGE_USERS,
@@ -6074,6 +6076,8 @@
      */
     public void setOrganizationColorForUser(@ColorInt int color, @UserIdInt int userId) {
         try {
+            // always enforce alpha channel to have 100% opacity
+            color |= 0xFF000000;
             mService.setOrganizationColorForUser(color, userId);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
@@ -6085,10 +6089,10 @@
      * This color is used as background color of the confirm credentials screen for that user.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @return The 32bit representation of the color to be used.
+     * @return The 24bit (0xRRGGBB) representation of the color to be used.
      * @throws SecurityException if {@code admin} is not a profile owner.
      */
-    public int getOrganizationColor(@NonNull ComponentName admin) {
+    public @ColorInt int getOrganizationColor(@NonNull ComponentName admin) {
         try {
             return mService.getOrganizationColor(admin);
         } catch (RemoteException re) {
@@ -6101,9 +6105,9 @@
      * Retrieve the customization color for a given user.
      *
      * @param userHandle The user id of the user we're interested in.
-     * @return The 32bit representation of the color to be used.
+     * @return The 24bit (0xRRGGBB) representation of the color to be used.
      */
-    public int getOrganizationColorForUser(int userHandle) {
+    public @ColorInt int getOrganizationColorForUser(int userHandle) {
         try {
             return mService.getOrganizationColorForUser(userHandle);
         } catch (RemoteException re) {
@@ -6123,7 +6127,7 @@
      * @param title The organization name or {@code null} to clear a previously set name.
      * @throws SecurityException if {@code admin} is not a profile owner.
      */
-    public void setOrganizationName(@NonNull ComponentName admin, @Nullable String title) {
+    public void setOrganizationName(@NonNull ComponentName admin, @Nullable CharSequence title) {
         try {
             mService.setOrganizationName(admin, title);
         } catch (RemoteException re) {
@@ -6139,7 +6143,7 @@
      * @return The organization name or {@code null} if none is set.
      * @throws SecurityException if {@code admin} is not a profile owner.
      */
-    public String getOrganizationName(@NonNull ComponentName admin) {
+    public CharSequence getOrganizationName(@NonNull ComponentName admin) {
         try {
             return mService.getOrganizationName(admin);
         } catch (RemoteException re) {
@@ -6155,7 +6159,7 @@
      *
      * @hide
      */
-    public String getOrganizationNameForUser(int userHandle) {
+    public CharSequence getOrganizationNameForUser(int userHandle) {
         try {
             return mService.getOrganizationNameForUser(userHandle);
         } catch (RemoteException re) {
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 6df1038..2801b87 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -284,9 +284,9 @@
     int getOrganizationColor(in ComponentName admin);
     int getOrganizationColorForUser(int userHandle);
 
-    void setOrganizationName(in ComponentName admin, in String title);
-    String getOrganizationName(in ComponentName admin);
-    String getOrganizationNameForUser(int userHandle);
+    void setOrganizationName(in ComponentName admin, in CharSequence title);
+    CharSequence getOrganizationName(in ComponentName admin);
+    CharSequence getOrganizationNameForUser(int userHandle);
 
     int getUserProvisioningState();
     void setUserProvisioningState(int state, int userHandle);
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 9b4f43a..09050b6 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -138,6 +138,20 @@
      */
     public static final int PRIORITY_TOP_APP = 40;
 
+    /**
+     * Adjustment of {@link #getPriority} if the app has often (50% or more of the time)
+     * been running jobs.
+     * @hide
+     */
+    public static final int PRIORITY_ADJ_OFTEN_RUNNING = -40;
+
+    /**
+     * Adjustment of {@link #getPriority} if the app has always (90% or more of the time)
+     * been running jobs.
+     * @hide
+     */
+    public static final int PRIORITY_ADJ_ALWAYS_RUNNING = -80;
+
     private final int jobId;
     private final PersistableBundle extras;
     private final ComponentName service;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7e67e8d..831de4a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -765,6 +765,19 @@
             = "android.intent.action.APPLICATION_PREFERENCES";
 
     /**
+     * Activity Action: Launch an activity showing the app information.
+     * For applications which install other applications (such as app stores), it is recommended
+     * to handle this action for providing the app information to the user.
+     *
+     * <p>Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose information needs
+     * to be displayed.
+     * <p>Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SHOW_APP_INFO
+            = "android.intent.action.SHOW_APP_INFO";
+
+    /**
      * Represents a shortcut/live folder icon resource.
      *
      * @see Intent#ACTION_CREATE_SHORTCUT
@@ -1683,9 +1696,7 @@
      * Type: String
      * </p>
      *
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
 
     /**
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 94ce57a..239f2d0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -683,7 +683,7 @@
                 // interface.
                 int leftLen = mLeftIndents == null ? 0 : mLeftIndents.length;
                 int rightLen = mRightIndents == null ? 0 : mRightIndents.length;
-                int indentsLen = Math.max(1, Math.min(leftLen, rightLen) - mLineCount);
+                int indentsLen = Math.max(1, Math.max(leftLen, rightLen) - mLineCount);
                 int[] indents = new int[indentsLen];
                 for (int i = 0; i < indentsLen; i++) {
                     int leftMargin = mLeftIndents == null ? 0 :
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index a324767..2ce43c8 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -549,8 +549,7 @@
                 // Compute surface insets required to draw at specified Z value.
                 // TODO: Use real shadow insets for a constant max Z.
                 if (!attrs.hasManualSurfaceInsets) {
-                    final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
-                    attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+                    attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
                 }
 
                 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
@@ -883,10 +882,12 @@
             }
             mWindowAttributes.privateFlags |= compatibleWindowFlag;
 
-            // Restore old surface insets.
-            mWindowAttributes.surfaceInsets.set(
-                    oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
-            mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
+            if (mWindowAttributes.preservePreviousSurfaceInsets) {
+                // Restore old surface insets.
+                mWindowAttributes.surfaceInsets.set(
+                        oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
+                mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
+            }
 
             applyKeepScreenOnFlag(mWindowAttributes);
 
@@ -3373,6 +3374,16 @@
         }
 
         @Override
+        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+            if (msg.what == MSG_REQUEST_KEYBOARD_SHORTCUTS && msg.obj == null) {
+                // Debugging for b/27963013
+                throw new NullPointerException(
+                        "Attempted to call MSG_REQUEST_KEYBOARD_SHORTCUTS with null receiver:");
+            }
+            return super.sendMessageAtTime(msg, uptimeMillis);
+        }
+
+        @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
             case MSG_INVALIDATE:
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 584233c..e3de810 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1482,6 +1482,16 @@
         public boolean hasManualSurfaceInsets;
 
         /**
+         * Whether the previous surface insets should be used vs. what is currently set. When set
+         * to {@code true}, the view root will ignore surfaces insets in this object and use what
+         * it currently has.
+         *
+         * @see #surfaceInsets
+         * @hide
+         */
+        public boolean preservePreviousSurfaceInsets = true;
+
+        /**
          * The desired bitmap format.  May be one of the constants in
          * {@link android.graphics.PixelFormat}.  Default is OPAQUE.
          */
@@ -1771,6 +1781,17 @@
             return mTitle != null ? mTitle : "";
         }
 
+        /**
+         * Sets the surface insets based on the elevation (visual z position) of the input view.
+         * @hide
+         */
+        public final void setSurfaceInsets(View view, boolean manual, boolean preservePrevious) {
+            final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
+            surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+            hasManualSurfaceInsets = manual;
+            preservePreviousSurfaceInsets = preservePrevious;
+        }
+
         /** @hide */
         @SystemApi
         public final void setUserActivityTimeout(long timeout) {
@@ -1822,6 +1843,7 @@
             out.writeInt(surfaceInsets.right);
             out.writeInt(surfaceInsets.bottom);
             out.writeInt(hasManualSurfaceInsets ? 1 : 0);
+            out.writeInt(preservePreviousSurfaceInsets ? 1 : 0);
             out.writeInt(needsMenuKey);
             out.writeInt(accessibilityIdOfAnchor);
             TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
@@ -1874,6 +1896,7 @@
             surfaceInsets.right = in.readInt();
             surfaceInsets.bottom = in.readInt();
             hasManualSurfaceInsets = in.readInt() != 0;
+            preservePreviousSurfaceInsets = in.readInt() != 0;
             needsMenuKey = in.readInt();
             accessibilityIdOfAnchor = in.readInt();
             accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
@@ -2075,6 +2098,11 @@
                 changes |= SURFACE_INSETS_CHANGED;
             }
 
+            if (preservePreviousSurfaceInsets != o.preservePreviousSurfaceInsets) {
+                preservePreviousSurfaceInsets = o.preservePreviousSurfaceInsets;
+                changes |= SURFACE_INSETS_CHANGED;
+            }
+
             if (needsMenuKey != o.needsMenuKey) {
                 needsMenuKey = o.needsMenuKey;
                 changes |= NEEDS_MENU_KEY_CHANGED;
@@ -2200,11 +2228,15 @@
                 sb.append(" userActivityTimeout=").append(userActivityTimeout);
             }
             if (surfaceInsets.left != 0 || surfaceInsets.top != 0 || surfaceInsets.right != 0 ||
-                    surfaceInsets.bottom != 0 || hasManualSurfaceInsets) {
+                    surfaceInsets.bottom != 0 || hasManualSurfaceInsets
+                    || !preservePreviousSurfaceInsets) {
                 sb.append(" surfaceInsets=").append(surfaceInsets);
                 if (hasManualSurfaceInsets) {
                     sb.append(" (manual)");
                 }
+                if (!preservePreviousSurfaceInsets) {
+                    sb.append(" (!preservePreviousSurfaceInsets)");
+                }
             }
             if (needsMenuKey != NEEDS_MENU_UNSET) {
                 sb.append(" needsMenuKey=");
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 0d8d8ed..af46756 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1290,9 +1290,7 @@
 
         // We may wrap that in another view, so we'll need to manually specify
         // the surface insets.
-        final int surfaceInset = (int) Math.ceil(mBackgroundView.getZ() * 2);
-        p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
-        p.hasManualSurfaceInsets = true;
+        p.setSurfaceInsets(mBackgroundView, true /*manual*/, true /*preservePrevious*/);
 
         mPopupViewInitialLayoutDirectionInherited =
                 (mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
@@ -1581,7 +1579,7 @@
             return true;
         }
 
-        final int spaceAbove = displayFrameTop + anchorTopInScreen - anchorHeight;
+        final int spaceAbove = anchorTopInScreen - anchorHeight - displayFrameTop;
         if (height <= spaceAbove) {
             // Move everything up.
             if (mOverlapAnchor) {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index e9fa26c..9c9784b 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1347,6 +1347,13 @@
 
         if (d instanceof LayerDrawable) {
             d = ((LayerDrawable) d).findDrawableByLayerId(id);
+            if (d == null) {
+                // If we can't find the requested layer, fall back to setting
+                // the level of the entire drawable. This will break if
+                // progress is set on multiple elements, but the theme-default
+                // drawable will always have all layer IDs present.
+                d = mCurrentDrawable;
+            }
         }
 
         if (d != null) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index d2ff9bc4..fe63267 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -1403,10 +1403,12 @@
     @Override
     public final void setElevation(float elevation) {
         mElevation = elevation;
+        final WindowManager.LayoutParams attrs = getAttributes();
         if (mDecor != null) {
             mDecor.setElevation(elevation);
+            attrs.setSurfaceInsets(mDecor, true /*manual*/, false /*preservePrevious*/);
         }
-        dispatchWindowAttributesChanged(getAttributes());
+        dispatchWindowAttributesChanged(attrs);
     }
 
     @Override
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 50d86ff..0de6549 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -175,7 +175,7 @@
 
     PathParser::ParseResult result;
     PathData data;
-    PathParser::getPathDataFromString(&data, &result, pathString, stringLength);
+    PathParser::getPathDataFromAsciiString(&data, &result, pathString, stringLength);
     if (result.failureOccurred) {
         doThrowIAE(env, result.failureMessage.c_str());
     }
diff --git a/core/jni/android_util_PathParser.cpp b/core/jni/android_util_PathParser.cpp
index 0c867f1..53669a8 100644
--- a/core/jni/android_util_PathParser.cpp
+++ b/core/jni/android_util_PathParser.cpp
@@ -34,7 +34,7 @@
     SkPath* skPath = reinterpret_cast<SkPath*>(skPathHandle);
 
     PathParser::ParseResult result;
-    PathParser::parseStringForSkPath(skPath, &result, pathString, strLength);
+    PathParser::parseAsciiStringForSkPath(skPath, &result, pathString, strLength);
     env->ReleaseStringUTFChars(inputPathStr, pathString);
     if (result.failureOccurred) {
         doThrowIAE(env, result.failureMessage.c_str());
@@ -56,7 +56,7 @@
     const char* pathString = env->GetStringUTFChars(inputStr, NULL);
     PathData* pathData = new PathData();
     PathParser::ParseResult result;
-    PathParser::getPathDataFromString(pathData, &result, pathString, strLength);
+    PathParser::getPathDataFromAsciiString(pathData, &result, pathString, strLength);
     env->ReleaseStringUTFChars(inputStr, pathString);
     if (!result.failureOccurred) {
         return reinterpret_cast<jlong>(pathData);
diff --git a/graphics/java/android/graphics/PixelFormat.java b/graphics/java/android/graphics/PixelFormat.java
index 832b9c3..98082ca 100644
--- a/graphics/java/android/graphics/PixelFormat.java
+++ b/graphics/java/android/graphics/PixelFormat.java
@@ -16,8 +16,18 @@
 
 package android.graphics;
 
-public class PixelFormat
-{
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+public class PixelFormat {
+
+    /** @hide */
+    @IntDef({UNKNOWN, TRANSLUCENT, TRANSPARENT, OPAQUE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Opacity {}
+
     /* these constants need to match those in hardware/hardware.h */
 
     public static final int UNKNOWN     = 0;
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 4f600b4..1d95563 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -16,7 +16,14 @@
 
 package android.graphics.drawable;
 
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.AttrRes;
 import android.annotation.ColorInt;
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.ActivityInfo.Config;
@@ -47,17 +54,12 @@
 import android.util.Xml;
 import android.view.View;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
 import java.util.Arrays;
 import java.util.Collection;
 
-import com.android.internal.R;
-
 /**
  * A Drawable is a general abstraction for "something that can be drawn."  Most
  * often you will deal with Drawable as the type of resource retrieved for
@@ -148,7 +150,7 @@
      *
      * @param canvas The canvas to draw into
      */
-    public abstract void draw(Canvas canvas);
+    public abstract void draw(@NonNull Canvas canvas);
 
     /**
      * Specify a bounding rectangle for the Drawable. This is where the drawable
@@ -176,7 +178,7 @@
      * Specify a bounding rectangle for the Drawable. This is where the drawable
      * will draw when its draw() method is called.
      */
-    public void setBounds(Rect bounds) {
+    public void setBounds(@NonNull Rect bounds) {
         setBounds(bounds.left, bounds.top, bounds.right, bounds.bottom);
     }
 
@@ -188,7 +190,7 @@
      * @param bounds Rect to receive the drawable's bounds (allocated by the
      *               caller).
      */
-    public final void copyBounds(Rect bounds) {
+    public final void copyBounds(@NonNull Rect bounds) {
         bounds.set(mBounds);
     }
 
@@ -200,6 +202,7 @@
      *
      * @return A copy of the drawable's bounds
      */
+    @NonNull
     public final Rect copyBounds() {
         return new Rect(mBounds);
     }
@@ -219,6 +222,7 @@
      * @see #copyBounds()
      * @see #copyBounds(android.graphics.Rect)
      */
+    @NonNull
     public final Rect getBounds() {
         if (mBounds == ZERO_BOUNDS_RECT) {
             mBounds = new Rect();
@@ -237,6 +241,7 @@
      *
      * @return The dirty bounds of this drawable
      */
+    @NonNull
     public Rect getDirtyBounds() {
         return getBounds();
     }
@@ -354,8 +359,8 @@
      *
      * @see #getCallback()
      */
-    public final void setCallback(Callback cb) {
-        mCallback = new WeakReference<Callback>(cb);
+    public final void setCallback(@Nullable Callback cb) {
+        mCallback = cb != null ? new WeakReference<>(cb) : null;
     }
 
     /**
@@ -366,11 +371,9 @@
      *
      * @see #setCallback(android.graphics.drawable.Drawable.Callback)
      */
+    @Nullable
     public Callback getCallback() {
-        if (mCallback != null) {
-            return mCallback.get();
-        }
-        return null;
+        return mCallback != null ? mCallback.get() : null;
     }
 
     /**
@@ -399,7 +402,7 @@
      *
      * @see Callback#scheduleDrawable
      */
-    public void scheduleSelf(Runnable what, long when) {
+    public void scheduleSelf(@NonNull Runnable what, long when) {
         final Callback callback = getCallback();
         if (callback != null) {
             callback.scheduleDrawable(this, what, when);
@@ -415,7 +418,7 @@
      *
      * @see Callback#unscheduleDrawable
      */
-    public void unscheduleSelf(Runnable what) {
+    public void unscheduleSelf(@NonNull Runnable what) {
         final Callback callback = getCallback();
         if (callback != null) {
             callback.unscheduleDrawable(this, what);
@@ -429,7 +432,7 @@
      *         {@link android.view.View#LAYOUT_DIRECTION_RTL}
      * @see #setLayoutDirection(int)
      */
-    public int getLayoutDirection() {
+    public @View.ResolvedLayoutDir int getLayoutDirection() {
         return mLayoutDirection;
     }
 
@@ -467,7 +470,7 @@
      * Specify an alpha value for the drawable. 0 means fully transparent, and
      * 255 means fully opaque.
      */
-    public abstract void setAlpha(int alpha);
+    public abstract void setAlpha(@IntRange(from=0,to=255) int alpha);
 
     /**
      * Gets the current alpha value for the drawable. 0 means fully transparent,
@@ -476,6 +479,7 @@
      * The default return value is 255 if the class does not override this method to return a value
      * specific to its use of alpha.
      */
+    @IntRange(from=0,to=255)
     public int getAlpha() {
         return 0xFF;
     }
@@ -489,7 +493,7 @@
      * Drawables draw is private implementation detail, and not something apps
      * should rely upon.
      */
-    public void setXfermode(Xfermode mode) {
+    public void setXfermode(@Nullable Xfermode mode) {
         // Base implementation drops it on the floor for compatibility. Whee!
     }
 
@@ -592,7 +596,7 @@
      *
      * @return the current color filter, or {@code null} if none set
      */
-    public ColorFilter getColorFilter() {
+    public @Nullable ColorFilter getColorFilter() {
         return null;
     }
 
@@ -629,7 +633,7 @@
      * @param outRect the rect to populate with the hotspot bounds
      * @see #setHotspotBounds(int, int, int, int)
      */
-    public void getHotspotBounds(Rect outRect) {
+    public void getHotspotBounds(@NonNull Rect outRect) {
         outRect.set(getBounds());
     }
 
@@ -677,7 +681,7 @@
      * of the Drawable to change (hence requiring an invalidate), otherwise
      * returns false.
      */
-    public boolean setState(final int[] stateSet) {
+    public boolean setState(@NonNull final int[] stateSet) {
         if (!Arrays.equals(mStateSet, stateSet)) {
             mStateSet = stateSet;
             return onStateChange(stateSet);
@@ -692,7 +696,7 @@
      * Some drawables may modify their imagery based on the selected state.
      * @return An array of resource Ids describing the current state.
      */
-    public int[] getState() {
+    public @NonNull int[] getState() {
         return mStateSet;
     }
 
@@ -709,7 +713,7 @@
      *         {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable
      *         currently in use.
      */
-    public Drawable getCurrent() {
+    public @NonNull Drawable getCurrent() {
         return this;
     }
 
@@ -729,7 +733,7 @@
      * of the Drawable to change (hence requiring an invalidate), otherwise
      * returns false.
      */
-    public final boolean setLevel(int level) {
+    public final boolean setLevel(@IntRange(from=0,to=10000) int level) {
         if (mLevel != level) {
             mLevel = level;
             return onLevelChange(level);
@@ -742,7 +746,7 @@
      *
      * @return int Current level, from 0 (minimum) to 10000 (maximum).
      */
-    public final int getLevel() {
+    public final @IntRange(from=0,to=10000) int getLevel() {
         return mLevel;
     }
 
@@ -839,7 +843,7 @@
      *
      * @see android.graphics.PixelFormat
      */
-    public abstract int getOpacity();
+    public abstract @PixelFormat.Opacity int getOpacity();
 
     /**
      * Return the appropriate opacity value for two source opacities.  If
@@ -856,7 +860,8 @@
      *
      * @see #getOpacity
      */
-    public static int resolveOpacity(int op1, int op2) {
+    public static @PixelFormat.Opacity int resolveOpacity(@PixelFormat.Opacity int op1,
+            @PixelFormat.Opacity int op2) {
         if (op1 == op2) {
             return op1;
         }
@@ -885,7 +890,7 @@
      * report, else a Region holding the parts of the Drawable's bounds that
      * are transparent.
      */
-    public Region getTransparentRegion() {
+    public @Nullable Region getTransparentRegion() {
         return null;
     }
 
@@ -898,7 +903,10 @@
      * if it looks the same and there is no need to redraw it since its
      * last state.
      */
-    protected boolean onStateChange(int[] state) { return false; }
+    protected boolean onStateChange(int[] state) {
+        return false;
+    }
+
     /** Override this in your subclass to change appearance if you vary based
      *  on level.
      * @return Returns true if the level change has caused the appearance of
@@ -906,12 +914,17 @@
      * if it looks the same and there is no need to redraw it since its
      * last level.
      */
-    protected boolean onLevelChange(int level) { return false; }
+    protected boolean onLevelChange(int level) {
+        return false;
+    }
+
     /**
      * Override this in your subclass to change appearance if you vary based on
      * the bounds.
      */
-    protected void onBoundsChange(Rect bounds) {}
+    protected void onBoundsChange(Rect bounds) {
+        // Stub method.
+    }
 
     /**
      * Returns the drawable's intrinsic width.
@@ -986,7 +999,7 @@
      *
      * @hide
      */
-    public Insets getOpticalInsets() {
+    public @NonNull Insets getOpticalInsets() {
         return Insets.NONE;
     }
 
@@ -1020,7 +1033,7 @@
      * @see ConstantState
      * @see #getConstantState()
      */
-    public Drawable mutate() {
+    public @NonNull Drawable mutate() {
         return this;
     }
 
@@ -1126,9 +1139,10 @@
         AttributeSet attrs = Xml.asAttributeSet(parser);
 
         int type;
-        while ((type=parser.next()) != XmlPullParser.START_TAG &&
-                type != XmlPullParser.END_DOCUMENT) {
-            // Empty loop
+        //noinspection StatementWithEmptyBody
+        while ((type=parser.next()) != XmlPullParser.START_TAG
+                && type != XmlPullParser.END_DOCUMENT) {
+            // Empty loop.
         }
 
         if (type != XmlPullParser.START_TAG) {
@@ -1222,8 +1236,9 @@
      * @throws XmlPullParserException
      * @throws IOException
      */
-    void inflateWithAttributes(@NonNull Resources r, @NonNull XmlPullParser parser,
-            @NonNull TypedArray attrs, int visibleAttr) throws XmlPullParserException, IOException {
+    void inflateWithAttributes(@NonNull @SuppressWarnings("unused") Resources r,
+            @NonNull @SuppressWarnings("unused") XmlPullParser parser, @NonNull TypedArray attrs,
+            @AttrRes int visibleAttr) throws XmlPullParserException, IOException {
         mVisible = attrs.getBoolean(visibleAttr, mVisible);
     }
 
@@ -1254,8 +1269,7 @@
          * @return a new drawable object based on this constant state
          * @see {@link #newDrawable(Resources)}
          */
-        @NonNull
-        public abstract Drawable newDrawable();
+        public abstract @NonNull Drawable newDrawable();
 
         /**
          * Creates a new Drawable instance from its constant state using the
@@ -1269,8 +1283,7 @@
          *            be displayed
          * @return a new drawable object based on this constant state
          */
-        @NonNull
-        public Drawable newDrawable(@Nullable Resources res) {
+        public @NonNull Drawable newDrawable(@Nullable Resources res) {
             return newDrawable();
         }
 
@@ -1288,8 +1301,8 @@
          *              displayed
          * @return a new drawable object based on this constant state
          */
-        @NonNull
-        public Drawable newDrawable(@Nullable Resources res, @Nullable Theme theme) {
+        public @NonNull Drawable newDrawable(@Nullable Resources res,
+                @Nullable @SuppressWarnings("unused") Theme theme) {
             return newDrawable(res);
         }
 
@@ -1303,12 +1316,12 @@
          * @return Total pixel count
          * @hide
          */
-        public int addAtlasableBitmaps(Collection<Bitmap> atlasList) {
+        public int addAtlasableBitmaps(@NonNull Collection<Bitmap> atlasList) {
             return 0;
         }
 
         /** @hide */
-        protected final boolean isAtlasable(Bitmap bitmap) {
+        protected final boolean isAtlasable(@Nullable Bitmap bitmap) {
             return bitmap != null && bitmap.getConfig() == Bitmap.Config.ARGB_8888;
         }
 
@@ -1327,7 +1340,7 @@
      * @see ConstantState
      * @see Drawable#mutate()
      */
-    public ConstantState getConstantState() {
+    public @Nullable ConstantState getConstantState() {
         return null;
     }
 
@@ -1345,8 +1358,8 @@
      * Ensures the tint filter is consistent with the current tint color and
      * mode.
      */
-    PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint,
-            PorterDuff.Mode tintMode) {
+    @Nullable PorterDuffColorFilter updateTintFilter(@Nullable PorterDuffColorFilter tintFilter,
+            @Nullable ColorStateList tint, @Nullable PorterDuff.Mode tintMode) {
         if (tint == null || tintMode == null) {
             return null;
         }
@@ -1365,8 +1378,8 @@
      * Obtains styled attributes from the theme, if available, or unstyled
      * resources if the theme is null.
      */
-    static TypedArray obtainAttributes(
-            Resources res, Theme theme, AttributeSet set, int[] attrs) {
+    static @NonNull TypedArray obtainAttributes(@NonNull Resources res, @Nullable Theme theme,
+            @NonNull AttributeSet set, @NonNull int[] attrs) {
         if (theme == null) {
             return res.obtainAttributes(set, attrs);
         }
@@ -1418,8 +1431,6 @@
         final int rounded = Math.round(result);
         if (rounded != 0) {
             return rounded;
-        } else if (pixels == 0) {
-            return 0;
         } else if (pixels > 0) {
             return 1;
         } else {
@@ -1440,7 +1451,7 @@
      * @param cause the exception to re-throw
      * @throws RuntimeException
      */
-    static void rethrowAsRuntimeException(Exception cause) throws RuntimeException {
+    static void rethrowAsRuntimeException(@NonNull Exception cause) throws RuntimeException {
         final RuntimeException e = new RuntimeException(cause);
         e.setStackTrace(new StackTraceElement[0]);
         throw e;
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index bd71e0d..4d65782 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -226,7 +226,7 @@
         // Set to 0 so that the animate() basically instantly finishes
         mStartTime = 0;
     }
-    if (mDuration < 0 || mDuration > 50000) {
+    if (mDuration < 0) {
         ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
     }
 }
diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp
index 7e85333..2179f14 100644
--- a/libs/hwui/PathParser.cpp
+++ b/libs/hwui/PathParser.cpp
@@ -162,7 +162,7 @@
             || verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
 }
 
-void PathParser::getPathDataFromString(PathData* data, ParseResult* result,
+void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
         const char* pathStr, size_t strLen) {
     if (pathStr == NULL) {
         result->failureOccurred = true;
@@ -171,7 +171,16 @@
     }
 
     size_t start = 0;
-    size_t end = 1;
+    // Skip leading spaces.
+    while (isspace(pathStr[start]) && start < strLen) {
+        start++;
+    }
+    if (start == strLen) {
+        result->failureOccurred = true;
+        result->failureMessage = "Path string cannot be empty.";
+        return;
+    }
+    size_t end = start + 1;
 
     while (end < strLen) {
         end = nextStart(pathStr, strLen, end);
@@ -226,9 +235,9 @@
     ALOGD("points are : %s", os.str().c_str());
 }
 
-void PathParser::parseStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
+void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
     PathData pathData;
-    getPathDataFromString(&pathData, result, pathStr, strLen);
+    getPathDataFromAsciiString(&pathData, result, pathStr, strLen);
     if (result->failureOccurred) {
         return;
     }
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 180a7a3..5578e8d 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -39,9 +39,9 @@
     /**
      * Parse the string literal and create a Skia Path. Return true on success.
      */
-    ANDROID_API static void parseStringForSkPath(SkPath* outPath, ParseResult* result,
+    ANDROID_API static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result,
             const char* pathStr, size_t strLength);
-    ANDROID_API static void getPathDataFromString(PathData* outData, ParseResult* result,
+    ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
             const char* pathStr, size_t strLength);
     static void dump(const PathData& data);
     static bool isVerbValid(char verb);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index adfe45c..ac17ed2 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -96,7 +96,7 @@
 Path::Path(const char* pathStr, size_t strLength) {
     PathParser::ParseResult result;
     Data data;
-    PathParser::getPathDataFromString(&data, &result, pathStr, strLength);
+    PathParser::getPathDataFromAsciiString(&data, &result, pathStr, strLength);
     mStagingProperties.setData(data);
 }
 
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index e4c7ed7..691cfa01 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -40,11 +40,11 @@
 namespace uirenderer {
 
 namespace VectorDrawable {
-#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP_AND_NOTIFY(field, value) ? (flag = true, true) : false)
-#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
-#define VD_SET_PROP_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP(field, value);\
+#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
+#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
+#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
     onPropertyChanged(); retVal;})
-#define UPDATE_SKPROP(field, value) ({bool retVal = (field != value); if (field != value) SkRefCnt_SafeAssign(field, value); retVal;})
+#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
 
 /* A VectorDrawable is composed of a tree of nodes.
  * Each node can be a group node, or a path.
@@ -248,49 +248,49 @@
             return mPrimitiveFields.strokeWidth;
         }
         void setStrokeWidth(float strokeWidth) {
-            VD_SET_PROP_AND_NOTIFY(strokeWidth, strokeWidth);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
         }
         SkColor getStrokeColor() const{
             return mPrimitiveFields.strokeColor;
         }
         void setStrokeColor(SkColor strokeColor) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeColor, strokeColor);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
         }
         float getStrokeAlpha() const{
             return mPrimitiveFields.strokeAlpha;
         }
         void setStrokeAlpha(float strokeAlpha) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeAlpha, strokeAlpha);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
         }
         SkColor getFillColor() const {
             return mPrimitiveFields.fillColor;
         }
         void setFillColor(SkColor fillColor) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillColor, fillColor);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
         }
         float getFillAlpha() const{
             return mPrimitiveFields.fillAlpha;
         }
         void setFillAlpha(float fillAlpha) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillAlpha, fillAlpha);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
         }
         float getTrimPathStart() const{
             return mPrimitiveFields.trimPathStart;
         }
         void setTrimPathStart(float trimPathStart) {
-            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathStart, trimPathStart, mTrimDirty);
+            VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
         }
         float getTrimPathEnd() const{
             return mPrimitiveFields.trimPathEnd;
         }
         void setTrimPathEnd(float trimPathEnd) {
-            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathEnd, trimPathEnd, mTrimDirty);
+            VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
         }
         float getTrimPathOffset() const{
             return mPrimitiveFields.trimPathOffset;
         }
         void setTrimPathOffset(float trimPathOffset) {
-            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathOffset, trimPathOffset, mTrimDirty);
+            VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
         }
 
         float getStrokeMiterLimit() const {
@@ -425,43 +425,43 @@
             return mPrimitiveFields.rotate;
         }
         void setRotation(float rotation) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.rotate, rotation);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
         }
         float getPivotX() const {
             return mPrimitiveFields.pivotX;
         }
         void setPivotX(float pivotX) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotX, pivotX);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
         }
         float getPivotY() const {
             return mPrimitiveFields.pivotY;
         }
         void setPivotY(float pivotY) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotY, pivotY);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
         }
         float getScaleX() const {
             return mPrimitiveFields.scaleX;
         }
         void setScaleX(float scaleX) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleX, scaleX);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
         }
         float getScaleY() const {
             return mPrimitiveFields.scaleY;
         }
         void setScaleY(float scaleY) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleY, scaleY);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
         }
         float getTranslateX() const {
             return mPrimitiveFields.translateX;
         }
         void setTranslateX(float translateX) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.translateX, translateX);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
         }
         float getTranslateY() const {
             return mPrimitiveFields.translateY;
         }
         void setTranslateY(float translateY) {
-            VD_SET_PROP_AND_NOTIFY(translateY, translateY);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
         }
         void updateProperties(float rotate, float pivotX, float pivotY,
                 float scaleX, float scaleY, float translateX, float translateY) {
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index 4186539..b43c4c3 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -31,7 +31,7 @@
     size_t length = strlen(sPathString);
     PathParser::ParseResult result;
     while (state.KeepRunning()) {
-        PathParser::parseStringForSkPath(&skPath, &result, sPathString, length);
+        PathParser::parseAsciiStringForSkPath(&skPath, &result, sPathString, length);
         benchmark::DoNotOptimize(&result);
         benchmark::DoNotOptimize(&skPath);
     }
@@ -43,7 +43,7 @@
     PathData outData;
     PathParser::ParseResult result;
     while (state.KeepRunning()) {
-        PathParser::getPathDataFromString(&outData, &result, sPathString, length);
+        PathParser::getPathDataFromAsciiString(&outData, &result, sPathString, length);
         benchmark::DoNotOptimize(&result);
         benchmark::DoNotOptimize(&outData);
     }
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 796169e..83b485f 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -234,9 +234,10 @@
     {"3e...3", false}, // Not starting with a verb and ill-formatted float
     {"L.M.F.A.O", false}, // No floats following verbs
     {"m 1 1", true}, // Valid path data
-    {"z", true}, // Valid path data
+    {"\n \t   z", true}, // Valid path data with leading spaces
     {"1-2e34567", false}, // Not starting with a verb and ill-formatted float
-    {"f 4 5", false} // Invalid verb
+    {"f 4 5", false}, // Invalid verb
+    {"\r      ", false} // Empty string
 };
 
 
@@ -250,7 +251,7 @@
         // Test generated path data against the given data.
         PathData pathData;
         size_t length = strlen(testData.pathString);
-        PathParser::getPathDataFromString(&pathData, &result, testData.pathString, length);
+        PathParser::getPathDataFromAsciiString(&pathData, &result, testData.pathString, length);
         EXPECT_EQ(testData.pathData, pathData);
     }
 
@@ -258,7 +259,7 @@
         PathParser::ParseResult result;
         PathData pathData;
         SkPath skPath;
-        PathParser::getPathDataFromString(&pathData, &result,
+        PathParser::getPathDataFromAsciiString(&pathData, &result,
                 stringPath.stringPath, strlen(stringPath.stringPath));
         EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
     }
@@ -274,13 +275,13 @@
     }
 }
 
-TEST(PathParser, parseStringForSkPath) {
+TEST(PathParser, parseAsciiStringForSkPath) {
     for (TestData testData: sTestDataSet) {
         PathParser::ParseResult result;
         size_t length = strlen(testData.pathString);
         // Check the return value as well as the SkPath generated.
         SkPath actualPath;
-        PathParser::parseStringForSkPath(&actualPath, &result, testData.pathString, length);
+        PathParser::parseAsciiStringForSkPath(&actualPath, &result, testData.pathString, length);
         bool hasValidData = !result.failureOccurred;
         EXPECT_EQ(hasValidData, testData.pathData.verbs.size() > 0);
         SkPath expectedPath;
@@ -291,7 +292,7 @@
     for (StringPath stringPath : sStringPaths) {
         PathParser::ParseResult result;
         SkPath skPath;
-        PathParser::parseStringForSkPath(&skPath, &result, stringPath.stringPath,
+        PathParser::parseAsciiStringForSkPath(&skPath, &result, stringPath.stringPath,
                 strlen(stringPath.stringPath));
         EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
     }
@@ -390,5 +391,40 @@
         EXPECT_EQ(matrixAndScale.matrixScale, actualMatrixScale);
     }
 }
+
+TEST(VectorDrawable, groupProperties) {
+    //TODO: Also need to test property sync and dirty flag when properties change.
+    VectorDrawable::Group group;
+    VectorDrawable::Group::GroupProperties* properties = group.mutateProperties();
+    // Test default values, change values through setters and verify the change through getters.
+    EXPECT_EQ(0.0f, properties->getTranslateX());
+    properties->setTranslateX(1.0f);
+    EXPECT_EQ(1.0f, properties->getTranslateX());
+
+    EXPECT_EQ(0.0f, properties->getTranslateY());
+    properties->setTranslateY(1.0f);
+    EXPECT_EQ(1.0f, properties->getTranslateY());
+
+    EXPECT_EQ(0.0f, properties->getRotation());
+    properties->setRotation(1.0f);
+    EXPECT_EQ(1.0f, properties->getRotation());
+
+    EXPECT_EQ(1.0f, properties->getScaleX());
+    properties->setScaleX(0.0f);
+    EXPECT_EQ(0.0f, properties->getScaleX());
+
+    EXPECT_EQ(1.0f, properties->getScaleY());
+    properties->setScaleY(0.0f);
+    EXPECT_EQ(0.0f, properties->getScaleY());
+
+    EXPECT_EQ(0.0f, properties->getPivotX());
+    properties->setPivotX(1.0f);
+    EXPECT_EQ(1.0f, properties->getPivotX());
+
+    EXPECT_EQ(0.0f, properties->getPivotY());
+    properties->setPivotY(1.0f);
+    EXPECT_EQ(1.0f, properties->getPivotY());
+
+}
 }; // namespace uirenderer
 }; // namespace android
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h
index d388388..9096aeb 100644
--- a/media/jni/soundpool/SoundPoolThread.h
+++ b/media/jni/soundpool/SoundPoolThread.h
@@ -47,7 +47,7 @@
     void write(SoundPoolMsg msg);
 
 private:
-    static const size_t maxMessages = 5;
+    static const size_t maxMessages = 128;
 
     static int beginThread(void* arg);
     int run();
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index 3197abd..568e200 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -2,6 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := optional
+LOCAL_PRIVILEGED_MODULE := true
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index e7b2ed1..fba25ab 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -1110,7 +1110,7 @@
         List<String> enabled = new ArrayList<String>();
         for (String id : mAdapter.getModelIds()) {
             Cursor cursor = getModel().getItem(id);
-            if (cursor != null) {
+            if (cursor == null) {
                 Log.w(TAG, "Skipping selection. Can't obtain cursor for modeId: " + id);
                 continue;
             }
@@ -1202,7 +1202,7 @@
             String id = getModelId(v);
             if (id != null) {
                 Cursor dstCursor = mModel.getItem(id);
-                if (dstCursor != null) {
+                if (dstCursor == null) {
                     Log.w(TAG, "Invalid destination. Can't obtain cursor for modelId: " + id);
                     return null;
                 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index e7aebdd..c411186 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -320,6 +320,8 @@
                 mFileProvider, new RemotePrintDocument.RemoteAdapterDeathObserver() {
             @Override
             public void onDied() {
+                Log.w(LOG_TAG, "Printing app died unexpectedly");
+
                 // If we are finishing or we are in a state that we do not need any
                 // data from the printing app, then no need to finish.
                 if (isFinishing() || (isFinalState(mState) && !mPrintedDocument.isUpdating())) {
diff --git a/packages/Shell/res/layout/confirm_repeat.xml b/packages/Shell/res/layout/confirm_repeat.xml
index d12f467..ad90af1 100644
--- a/packages/Shell/res/layout/confirm_repeat.xml
+++ b/packages/Shell/res/layout/confirm_repeat.xml
@@ -38,5 +38,5 @@
         android:id="@android:id/checkbox"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:text="@string/bugreport_confirm_repeat" />
+        android:text="@string/bugreport_confirm_dont_repeat" />
 </LinearLayout>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index bee15dd..95e36fd 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -35,9 +35,9 @@
     <string name="bugreport_finished_pending_screenshot_text" product="default">Tap to share your bug report without a screenshot or wait for the screenshot to finish</string>
 
     <!-- Body of dialog informing user about contents of a bugreport. [CHAR LIMIT=NONE] -->
-    <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, including personal and private information.  Only share bug reports with apps and people you trust.</string>
-    <!-- Checkbox that indicates this dialog should be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
-    <string name="bugreport_confirm_repeat">Show this message next time</string>
+    <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, which may include data you consider sensitive (such as app-usage and location data). Only share bug reports with people and apps you trust.</string>
+    <!-- Checkbox that indicates this dialog should not be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
+    <string name="bugreport_confirm_dont_repeat">Don\'t show again</string>
 
     <!-- Title for documents backend that offers bugreports. -->
     <string name="bugreport_storage_title">Bug reports</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportPrefs.java b/packages/Shell/src/com/android/shell/BugreportPrefs.java
index 3748e89..93690d4 100644
--- a/packages/Shell/src/com/android/shell/BugreportPrefs.java
+++ b/packages/Shell/src/com/android/shell/BugreportPrefs.java
@@ -22,22 +22,24 @@
 /**
  * Preferences related to bug reports.
  */
-public class BugreportPrefs {
-    private static final String PREFS_BUGREPORT = "bugreports";
+final class BugreportPrefs {
+    static final String PREFS_BUGREPORT = "bugreports";
 
     private static final String KEY_WARNING_STATE = "warning-state";
 
-    public static final int STATE_UNKNOWN = 0;
-    public static final int STATE_SHOW = 1;
-    public static final int STATE_HIDE = 2;
+    static final int STATE_UNKNOWN = 0;
+    // Shows the warning dialog.
+    static final int STATE_SHOW = 1;
+    // Skips the warning dialog.
+    static final int STATE_HIDE = 2;
 
-    public static int getWarningState(Context context, int def) {
+    static int getWarningState(Context context, int def) {
         final SharedPreferences prefs = context.getSharedPreferences(
                 PREFS_BUGREPORT, Context.MODE_PRIVATE);
         return prefs.getInt(KEY_WARNING_STATE, def);
     }
 
-    public static void setWarningState(Context context, int value) {
+    static void setWarningState(Context context, int value) {
         final SharedPreferences prefs = context.getSharedPreferences(
                 PREFS_BUGREPORT, Context.MODE_PRIVATE);
         prefs.edit().putInt(KEY_WARNING_STATE, value).apply();
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index f0ddcb9..502eed1 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -17,7 +17,8 @@
 package com.android.shell;
 
 import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
-import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.STATE_HIDE;
+import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
 import static com.android.shell.BugreportPrefs.getWarningState;
 
 import java.io.BufferedOutputStream;
@@ -927,7 +928,7 @@
         final Intent notifIntent;
 
         // Send through warning dialog by default
-        if (getWarningState(mContext, STATE_SHOW) == STATE_SHOW) {
+        if (getWarningState(mContext, STATE_UNKNOWN) != STATE_HIDE) {
             notifIntent = buildWarningIntent(mContext, sendIntent);
         } else {
             notifIntent = sendIntent;
diff --git a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
index a1d879a..da33a65 100644
--- a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
+++ b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
@@ -59,7 +59,7 @@
         ap.mNegativeButtonListener = this;
 
         mConfirmRepeat = (CheckBox) ap.mView.findViewById(android.R.id.checkbox);
-        mConfirmRepeat.setChecked(getWarningState(this, STATE_UNKNOWN) == STATE_SHOW);
+        mConfirmRepeat.setChecked(getWarningState(this, STATE_UNKNOWN) != STATE_SHOW);
 
         setupAlert();
     }
@@ -68,7 +68,7 @@
     public void onClick(DialogInterface dialog, int which) {
         if (which == AlertDialog.BUTTON_POSITIVE) {
             // Remember confirm state, and launch target
-            setWarningState(this, mConfirmRepeat.isChecked() ? STATE_SHOW : STATE_HIDE);
+            setWarningState(this, mConfirmRepeat.isChecked() ? STATE_HIDE : STATE_SHOW);
             startActivity(mSendIntent);
         }
 
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 3eb7754..537e4c5 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -17,7 +17,14 @@
 package com.android.shell;
 
 import static android.test.MoreAsserts.assertContainsRegex;
+
 import static com.android.shell.ActionSendMultipleConsumerActivity.UI_NAME;
+import static com.android.shell.BugreportPrefs.PREFS_BUGREPORT;
+import static com.android.shell.BugreportPrefs.STATE_HIDE;
+import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
+import static com.android.shell.BugreportPrefs.getWarningState;
+import static com.android.shell.BugreportPrefs.setWarningState;
 import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
 import static com.android.shell.BugreportProgressService.EXTRA_ID;
 import static com.android.shell.BugreportProgressService.EXTRA_MAX;
@@ -48,12 +55,12 @@
 import java.util.zip.ZipOutputStream;
 
 import libcore.io.Streams;
+
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningServiceInfo;
 import android.app.Instrumentation;
 import android.app.NotificationManager;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
@@ -62,7 +69,6 @@
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.text.TextUtils;
@@ -70,7 +76,6 @@
 import android.util.Log;
 
 import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
-import com.android.shell.BugreportProgressService;
 
 /**
  * Integration tests for {@link BugreportReceiver}.
@@ -168,7 +173,7 @@
         }
         mDescription = sb.toString();
 
-        BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_HIDE);
+        setWarningState(mContext, STATE_HIDE);
     }
 
     public void testProgress() throws Exception {
@@ -500,9 +505,29 @@
         assertServiceNotRunning();
     }
 
-    public void testBugreportFinished_withWarning() throws Exception {
-        // Explicitly shows the warning.
-        BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
+    public void testBugreportFinished_withWarningFirstTime() throws Exception {
+        bugreportFinishedWithWarningTest(null);
+    }
+
+    public void testBugreportFinished_withWarningUnknownState() throws Exception {
+        bugreportFinishedWithWarningTest(STATE_UNKNOWN);
+    }
+
+    public void testBugreportFinished_withWarningShowAgain() throws Exception {
+        bugreportFinishedWithWarningTest(STATE_SHOW);
+    }
+
+    private void bugreportFinishedWithWarningTest(Integer propertyState) throws Exception {
+        if (propertyState == null) {
+            // Clear properties
+            mContext.getSharedPreferences(PREFS_BUGREPORT, Context.MODE_PRIVATE)
+                    .edit().clear().commit();
+            // Sanity check...
+            assertEquals("Did not reset properties", STATE_UNKNOWN,
+                    getWarningState(mContext, STATE_UNKNOWN));
+        } else {
+            setWarningState(mContext, propertyState);
+        }
 
         // Send notification and click on share.
         sendBugreportFinished(NO_ID, mPlainTextPath, null);
@@ -510,10 +535,16 @@
 
         // Handle the warning
         mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
-        // TODO: get ok and showMessageAgain from the dialog reference above
-        UiObject showMessageAgain =
-                mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_repeat));
-        mUiBot.click(showMessageAgain, "show-message-again");
+        // TODO: get ok and dontShowAgain from the dialog reference above
+        UiObject dontShowAgain =
+                mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_dont_repeat));
+        final boolean firstTime = propertyState == null || propertyState == STATE_UNKNOWN;
+        if (firstTime) {
+            assertTrue("Checkbox should be checked by default", dontShowAgain.isChecked());
+        } else {
+            assertFalse("Checkbox should not be checked", dontShowAgain.isChecked());
+            mUiBot.click(dontShowAgain, "dont-show-again");
+        }
         UiObject ok = mUiBot.getVisibleObject(mContext.getString(com.android.internal.R.string.ok));
         mUiBot.click(ok, "ok");
 
@@ -523,8 +554,8 @@
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
 
         // Make sure it's hidden now.
-        int newState = BugreportPrefs.getWarningState(mContext, BugreportPrefs.STATE_UNKNOWN);
-        assertEquals("Didn't change state", BugreportPrefs.STATE_HIDE, newState);
+        int newState = getWarningState(mContext, STATE_UNKNOWN);
+        assertEquals("Didn't change state", STATE_HIDE, newState);
     }
 
     public void testShareBugreportAfterServiceDies() throws Exception {
@@ -876,8 +907,8 @@
     }
 
     private String getPath(String file) {
-        File rootDir = new ContextWrapper(mContext).getFilesDir();
-        File dir = new File(rootDir, BUGREPORTS_DIR);
+        final File rootDir = mContext.getFilesDir();
+        final File dir = new File(rootDir, BUGREPORTS_DIR);
         if (!dir.exists()) {
             Log.i(TAG, "Creating directory " + dir);
             assertTrue("Could not create directory " + dir, dir.mkdir());
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index a130cf9..1af9075 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -100,10 +100,12 @@
 
     </PreferenceScreen>
 
+    <!--
     <Preference
         android:key="color_transform"
         android:title="@string/color_and_appearance"
         android:fragment="com.android.systemui.tuner.ColorAndAppearanceFragment" />
+    -->
 
     <PreferenceScreen
         android:key="volume_and_do_not_disturb"
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
index ae104cd..5e5da74 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerActivity.java
@@ -36,7 +36,8 @@
         super.onCreate(savedInstanceState);
 
         if (getFragmentManager().findFragmentByTag(TAG_TUNER) == null) {
-            boolean showDemoMode = getIntent().getAction().equals(
+            final String action = getIntent().getAction();
+            boolean showDemoMode = action != null && action.equals(
                     "com.android.settings.action.DEMO_MODE");
             boolean showNightMode = getIntent().getBooleanExtra(
                     NightModeFragment.EXTRA_SHOW_NIGHT_MODE, false);
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 6ca3af8..0428ecf 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -613,23 +613,22 @@
                             | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                 }
             }
+            for (int j = 0; j < widgetCount; j++) {
+                Widget widget = provider.widgets.get(j);
+                if (targetWidget != null && targetWidget != widget) continue;
+                PendingIntent intent = null;
+                if (onClickIntent != null) {
+                    intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
+                            onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+                }
+                RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
+                if (widget.replaceWithMaskedViewsLocked(views)) {
+                    scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
+                }
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
-
-        for (int j = 0; j < widgetCount; j++) {
-            Widget widget = provider.widgets.get(j);
-            if (targetWidget != null && targetWidget != widget) continue;
-            PendingIntent intent = null;
-            if (onClickIntent != null) {
-                intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
-                        onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-            }
-            RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
-            if (widget.replaceWithMaskedViewsLocked(views)) {
-                scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
-            }
-        }
     }
 
     private void unmaskWidgetsViewsLocked(Provider provider) {
@@ -1062,8 +1061,6 @@
             widget.provider = provider;
             widget.options = (options != null) ? cloneIfLocalBinder(options) : new Bundle();
 
-            onWidgetProviderAddedOrChangedLocked(widget);
-
             // We need to provide a default value for the widget category if it is not specified
             if (!widget.options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) {
                 widget.options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
@@ -1072,6 +1069,8 @@
 
             provider.widgets.add(widget);
 
+            onWidgetProviderAddedOrChangedLocked(widget);
+
             final int widgetCount = provider.widgets.size();
             if (widgetCount == 1) {
                 // Tell the provider that it's ready.
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index bf4df94..fffd850 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -174,6 +174,16 @@
         public static final int StrictCleartext           = 617;
     }
 
+    /**
+     * String indicating a softap command.
+     */
+    static final String SOFT_AP_COMMAND = "softap";
+
+    /**
+     * String passed back to netd connector indicating softap command success.
+     */
+    static final String SOFT_AP_COMMAND_SUCCESS = "Ok";
+
     static final int DAEMON_MSG_MOBILE_CONN_REAL_TIME_INFO = 1;
 
     /**
@@ -1426,20 +1436,48 @@
         }
     }
 
+    /**
+     * Private method used to call execute for a command given the provided arguments.
+     *
+     * This function checks the returned NativeDaemonEvent for the provided expected response code
+     * and message.  If either of these is not correct, an error is logged.
+     *
+     * @param String command The command to execute.
+     * @param Object[] args If needed, arguments for the command to execute.
+     * @param int expectedResponseCode The code expected to be returned in the corresponding event.
+     * @param String expectedResponseMessage The message expected in the returned event.
+     * @param String logMsg The message to log as an error (TAG will be applied).
+     */
+    private void executeOrLogWithMessage(String command, Object[] args,
+            int expectedResponseCode, String expectedResponseMessage, String logMsg)
+            throws NativeDaemonConnectorException {
+        NativeDaemonEvent event = mConnector.execute(command, args);
+        if (event.getCode() != expectedResponseCode
+                || !event.getMessage().equals(expectedResponseMessage)) {
+            Log.e(TAG, logMsg + ": event = " + event);
+        }
+    }
+
     @Override
-    public void startAccessPoint(
-            WifiConfiguration wifiConfig, String wlanIface) {
+    public void startAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        Object[] args;
+        String logMsg = "startAccessPoint Error setting up softap";
         try {
             if (wifiConfig == null) {
-                mConnector.execute("softap", "set", wlanIface);
+                args = new Object[] {"set", wlanIface};
             } else {
-                mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
-                                   "broadcast", Integer.toString(wifiConfig.apChannel),
-                                   getSecurityType(wifiConfig),
-                                   new SensitiveArg(wifiConfig.preSharedKey));
+                args = new Object[] {"set", wlanIface, wifiConfig.SSID,
+                        "broadcast", Integer.toString(wifiConfig.apChannel),
+                        getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
             }
-            mConnector.execute("softap", "startap");
+            executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+                    SOFT_AP_COMMAND_SUCCESS, logMsg);
+
+            logMsg = "startAccessPoint Error starting softap";
+            args = new Object[] {"startap"};
+            executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+                    SOFT_AP_COMMAND_SUCCESS, logMsg);
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
@@ -1460,8 +1498,12 @@
     @Override
     public void wifiFirmwareReload(String wlanIface, String mode) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        Object[] args = {"fwreload", wlanIface, mode};
+        String logMsg = "wifiFirmwareReload Error reloading "
+                + wlanIface + " fw in " + mode + " mode";
         try {
-            mConnector.execute("softap", "fwreload", wlanIface, mode);
+            executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+                    SOFT_AP_COMMAND_SUCCESS, logMsg);
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
@@ -1470,8 +1512,12 @@
     @Override
     public void stopAccessPoint(String wlanIface) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        Object[] args = {"stopap"};
+        String logMsg = "stopAccessPoint Error stopping softap";
+
         try {
-            mConnector.execute("softap", "stopap");
+            executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+                    SOFT_AP_COMMAND_SUCCESS, logMsg);
             wifiFirmwareReload(wlanIface, "STA");
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
@@ -1481,14 +1527,21 @@
     @Override
     public void setAccessPoint(WifiConfiguration wifiConfig, String wlanIface) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
+        Object[] args;
+        String logMsg = "startAccessPoint Error setting up softap";
         try {
             if (wifiConfig == null) {
-                mConnector.execute("softap", "set", wlanIface);
+                args = new Object[] {"set", wlanIface};
             } else {
-                mConnector.execute("softap", "set", wlanIface, wifiConfig.SSID,
-                                   "broadcast", "6", getSecurityType(wifiConfig),
-                                   new SensitiveArg(wifiConfig.preSharedKey));
+                // TODO: understand why this is set to "6" instead of
+                // Integer.toString(wifiConfig.apChannel) as in startAccessPoint
+                // TODO: should startAccessPoint call this instead of repeating code?
+                args = new Object[] {"set", wlanIface, wifiConfig.SSID,
+                        "broadcast", "6",
+                        getSecurityType(wifiConfig), new SensitiveArg(wifiConfig.preSharedKey)};
             }
+            executeOrLogWithMessage(SOFT_AP_COMMAND, args, NetdResponseCode.SoftapStatusResult,
+                    SOFT_AP_COMMAND_SUCCESS, logMsg);
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c01b4f5..4c75f50 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9425,7 +9425,8 @@
             if (prev != null && prev.isRecentsActivity()) {
                 task.setTaskToReturnTo(ActivityRecord.RECENTS_ACTIVITY_TYPE);
             }
-            mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront");
+            mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront",
+                    false /* forceNonResizable */);
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 53c6024..598d9ff 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1759,8 +1759,8 @@
         }
     }
 
-    void findTaskToMoveToFrontLocked(
-            TaskRecord task, int flags, ActivityOptions options, String reason) {
+    void findTaskToMoveToFrontLocked(TaskRecord task, int flags, ActivityOptions options,
+            String reason, boolean forceNonResizeable) {
         if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
             mUserLeaving = true;
         }
@@ -1811,7 +1811,8 @@
         if (DEBUG_STACK) Slog.d(TAG_STACK,
                 "findTaskToMoveToFront: moved to front of stack=" + task.stack);
 
-        handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId);
+        handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+                forceNonResizeable);
     }
 
     boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
@@ -3360,19 +3361,25 @@
         }
     }
 
+    void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId, int actualStackId) {
+        handleNonResizableTaskIfNeeded(task, preferredStackId, actualStackId,
+                false /* forceNonResizable */);
+    }
+
     void handleNonResizableTaskIfNeeded(
-            TaskRecord task, int preferredStackId, int actualStackId) {
+            TaskRecord task, int preferredStackId, int actualStackId, boolean forceNonResizable) {
         if ((!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID)
                 || task.isHomeTask()) {
             return;
         }
 
-        if (!task.canGoInDockedStack()) {
+        if (!task.canGoInDockedStack() || forceNonResizable) {
             // Display a warning toast that we tried to put a non-dockable task in the docked stack.
             mService.mHandler.sendEmptyMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG);
 
-            // Dismiss docked stack.
-            mService.moveTasksToFullscreenStack(DOCKED_STACK_ID, false);
+            // Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
+            // we need to move it to top of fullscreen stack, otherwise it will be covered.
+            mService.moveTasksToFullscreenStack(DOCKED_STACK_ID, actualStackId == DOCKED_STACK_ID);
         } else if (task.mResizeMode == RESIZE_MODE_FORCE_RESIZEABLE) {
             String packageName = task.getTopActivity() != null
                     ? task.getTopActivity().appInfo.packageName : null;
@@ -3443,8 +3450,12 @@
         }
 
         if (andResume) {
-            findTaskToMoveToFrontLocked(task, 0, null, reason);
+            findTaskToMoveToFrontLocked(task, 0, null, reason,
+                    lockTaskModeState != LOCK_TASK_MODE_NONE);
             resumeFocusedStackTopActivityLocked();
+        } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
+            handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+                    true /* forceNonResizable */);
         }
     }
 
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index db41a54..8af0af0 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1402,24 +1402,12 @@
         }
     }
 
-    private void restoreLostPeriodicSyncsIfNeeded(int userId) {
-        List<SyncOperation> periodicSyncs = new ArrayList<SyncOperation>();
-        for (SyncOperation sync : getAllPendingSyncs()) {
-            if (sync.isPeriodic && sync.target.userId == userId) {
-                periodicSyncs.add(sync);
-            }
-        }
-        mSyncStorageEngine.restorePeriodicSyncsIfNeededForUser(userId, periodicSyncs);
-    }
-
     private void onUserUnlocked(int userId) {
         // Make sure that accounts we're about to use are valid.
         AccountManagerService.getSingleton().validateAccounts(userId);
 
         mSyncAdapters.invalidateCache(userId);
 
-        restoreLostPeriodicSyncsIfNeeded(userId);
-
         EndPoint target = new EndPoint(null, null, userId);
         updateRunningAccounts(target);
 
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index fb23265..bc3fc6a 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -826,35 +826,6 @@
         return true;
     }
 
-    /**
-     * STOPSHIP This is a temporary workaround and should be removed before shipping: b/28052438
-     */
-    void restorePeriodicSyncsIfNeededForUser(int userHandle, List<SyncOperation> periodicSyncs) {
-        if (mPeriodicSyncAddedListener == null) {
-            return;
-        }
-        synchronized (mAuthorities) {
-            for (int i = 0; i < mAuthorities.size(); i++) {
-                AuthorityInfo authority = mAuthorities.valueAt(i);
-                if (authority.target.userId == userHandle && authority.enabled) {
-                    boolean periodicSyncAlreadyExists = false;
-                    for (SyncOperation sync : periodicSyncs) {
-                        if (authority.target.matchesSpec(sync.target)) {
-                            periodicSyncAlreadyExists = true;
-                            break;
-                        }
-                    }
-                    // The periodic sync must have been lost due to previous bug.
-                    if (!periodicSyncAlreadyExists) {
-                        mPeriodicSyncAddedListener.onPeriodicSyncAdded(authority.target,
-                                new Bundle(), DEFAULT_POLL_FREQUENCY_SECONDS,
-                                calculateDefaultFlexTime(DEFAULT_POLL_FREQUENCY_SECONDS));
-                    }
-                }
-            }
-        }
-    }
-
     public void setMasterSyncAutomatically(boolean flag, int userId) {
         synchronized (mAuthorities) {
             Boolean auto = mMasterSyncAutomatically.get(userId);
diff --git a/services/core/java/com/android/server/job/JobPackageTracker.java b/services/core/java/com/android/server/job/JobPackageTracker.java
new file mode 100644
index 0000000..e5a2095
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobPackageTracker.java
@@ -0,0 +1,361 @@
+/*
+ * Copyright (C) 2016 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.server.job;
+
+import android.app.job.JobInfo;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+import com.android.server.job.controllers.JobStatus;
+
+import java.io.PrintWriter;
+
+public final class JobPackageTracker {
+    // We batch every 30 minutes.
+    static final long BATCHING_TIME = 30*60*1000;
+    // Number of historical data sets we keep.
+    static final int NUM_HISTORY = 5;
+
+    DataSet mCurDataSet = new DataSet();
+    DataSet[] mLastDataSets = new DataSet[NUM_HISTORY];
+
+    final static class PackageEntry {
+        long pastActiveTime;
+        long activeStartTime;
+        int activeCount;
+        boolean hadActive;
+        long pastActiveTopTime;
+        long activeTopStartTime;
+        int activeTopCount;
+        boolean hadActiveTop;
+        long pastPendingTime;
+        long pendingStartTime;
+        int pendingCount;
+        boolean hadPending;
+
+        public long getActiveTime(long now) {
+            long time = pastActiveTime;
+            if (activeCount > 0) {
+                time += now - activeStartTime;
+            }
+            return time;
+        }
+
+        public long getActiveTopTime(long now) {
+            long time = pastActiveTopTime;
+            if (activeTopCount > 0) {
+                time += now - activeTopStartTime;
+            }
+            return time;
+        }
+
+        public long getPendingTime(long now) {
+            long time = pastPendingTime;
+            if (pendingCount > 0) {
+                time += now - pendingStartTime;
+            }
+            return time;
+        }
+    }
+
+    final static class DataSet {
+        final SparseArray<ArrayMap<String, PackageEntry>> mEntries = new SparseArray<>();
+        final long mStartUptimeTime;
+        final long mStartElapsedTime;
+        final long mStartClockTime;
+        long mSummedTime;
+
+        public DataSet(DataSet otherTimes) {
+            mStartUptimeTime = otherTimes.mStartUptimeTime;
+            mStartElapsedTime = otherTimes.mStartElapsedTime;
+            mStartClockTime = otherTimes.mStartClockTime;
+        }
+
+        public DataSet() {
+            mStartUptimeTime = SystemClock.uptimeMillis();
+            mStartElapsedTime = SystemClock.elapsedRealtime();
+            mStartClockTime = System.currentTimeMillis();
+        }
+
+        private PackageEntry getOrCreateEntry(int uid, String pkg) {
+            ArrayMap<String, PackageEntry> uidMap = mEntries.get(uid);
+            if (uidMap == null) {
+                uidMap = new ArrayMap<>();
+                mEntries.put(uid, uidMap);
+            }
+            PackageEntry entry = uidMap.get(pkg);
+            if (entry == null) {
+                entry = new PackageEntry();
+                uidMap.put(pkg, entry);
+            }
+            return entry;
+        }
+
+        public PackageEntry getEntry(int uid, String pkg) {
+            ArrayMap<String, PackageEntry> uidMap = mEntries.get(uid);
+            if (uidMap == null) {
+                return null;
+            }
+            return uidMap.get(pkg);
+        }
+
+        long getTotalTime(long now) {
+            if (mSummedTime > 0) {
+                return mSummedTime;
+            }
+            return now - mStartUptimeTime;
+        }
+
+        void incPending(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.pendingCount == 0) {
+                pe.pendingStartTime = now;
+            }
+            pe.pendingCount++;
+        }
+
+        void decPending(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.pendingCount == 1) {
+                pe.pastPendingTime += now - pe.pendingStartTime;
+            }
+            pe.pendingCount--;
+        }
+
+        void incActive(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.activeCount == 0) {
+                pe.activeStartTime = now;
+            }
+            pe.activeCount++;
+        }
+
+        void decActive(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.activeCount == 1) {
+                pe.pastActiveTime += now - pe.activeStartTime;
+            }
+            pe.activeCount--;
+        }
+
+        void incActiveTop(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.activeTopCount == 0) {
+                pe.activeTopStartTime = now;
+            }
+            pe.activeTopCount++;
+        }
+
+        void decActiveTop(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.activeTopCount == 1) {
+                pe.pastActiveTopTime += now - pe.activeTopStartTime;
+            }
+            pe.activeTopCount--;
+        }
+
+        void finish(DataSet next, long now) {
+            for (int i = mEntries.size() - 1; i >= 0; i--) {
+                ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+                for (int j = uidMap.size() - 1; j >= 0; j--) {
+                    PackageEntry pe = uidMap.valueAt(j);
+                    if (pe.activeCount > 0 || pe.activeTopCount > 0 || pe.pendingCount > 0) {
+                        // Propagate existing activity in to next data set.
+                        PackageEntry nextPe = next.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j));
+                        nextPe.activeStartTime = now;
+                        nextPe.activeCount = pe.activeCount;
+                        nextPe.activeTopStartTime = now;
+                        nextPe.activeTopCount = pe.activeTopCount;
+                        nextPe.pendingStartTime = now;
+                        nextPe.pendingCount = pe.pendingCount;
+                        // Finish it off.
+                        if (pe.activeCount > 0) {
+                            pe.pastActiveTime += now - pe.activeStartTime;
+                            pe.activeCount = 0;
+                        }
+                        if (pe.activeTopCount > 0) {
+                            pe.pastActiveTopTime += now - pe.activeTopStartTime;
+                            pe.activeTopCount = 0;
+                        }
+                        if (pe.pendingCount > 0) {
+                            pe.pastPendingTime += now - pe.pendingStartTime;
+                            pe.pendingCount = 0;
+                        }
+                    }
+                }
+            }
+        }
+
+        void addTo(DataSet out, long now) {
+            out.mSummedTime += getTotalTime(now);
+            for (int i = mEntries.size() - 1; i >= 0; i--) {
+                ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+                for (int j = uidMap.size() - 1; j >= 0; j--) {
+                    PackageEntry pe = uidMap.valueAt(j);
+                    PackageEntry outPe = out.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j));
+                    outPe.pastActiveTime += pe.pastActiveTime;
+                    outPe.pastActiveTopTime += pe.pastActiveTopTime;
+                    outPe.pastPendingTime += pe.pastPendingTime;
+                    if (pe.activeCount > 0) {
+                        outPe.pastActiveTime += now - pe.activeStartTime;
+                        outPe.hadActive = true;
+                    }
+                    if (pe.activeTopCount > 0) {
+                        outPe.pastActiveTopTime += now - pe.activeTopStartTime;
+                        outPe.hadActiveTop = true;
+                    }
+                    if (pe.pendingCount > 0) {
+                        outPe.pastPendingTime += now - pe.pendingStartTime;
+                        outPe.hadPending = true;
+                    }
+                }
+            }
+        }
+
+        void printDuration(PrintWriter pw, long period, long duration, String suffix) {
+            float fraction = duration / (float) period;
+            int percent = (int) ((fraction * 100) + .5f);
+            if (percent > 0) {
+                pw.print(" ");
+                pw.print(percent);
+                pw.print("% ");
+                pw.print(suffix);
+            }
+        }
+
+        void dump(PrintWriter pw, String header, String prefix, long now, long nowEllapsed) {
+            final long period = getTotalTime(now);
+            pw.print(prefix); pw.print(header); pw.print(" at ");
+            pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", mStartClockTime).toString());
+            pw.print(" (");
+            TimeUtils.formatDuration(mStartElapsedTime, nowEllapsed, pw);
+            pw.print(") over ");
+            TimeUtils.formatDuration(period, pw);
+            pw.println(":");
+            final int NE = mEntries.size();
+            for (int i = 0; i < NE; i++) {
+                ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+                final int NP = uidMap.size();
+                for (int j = 0; j < NP; j++) {
+                    PackageEntry pe = uidMap.valueAt(j);
+                    pw.print(prefix); pw.print("  ");
+                    UserHandle.formatUid(pw, mEntries.keyAt(i));
+                    pw.print(" / "); pw.print(uidMap.keyAt(j));
+                    pw.print(":");
+                    printDuration(pw, period, pe.getPendingTime(now), "pending");
+                    printDuration(pw, period, pe.getActiveTime(now), "active");
+                    printDuration(pw, period, pe.getActiveTopTime(now), "active-top");
+                    if (pe.pendingCount > 0 || pe.hadPending) {
+                        pw.print(" (pending)");
+                    }
+                    if (pe.activeCount > 0 || pe.hadActive) {
+                        pw.print(" (active)");
+                    }
+                    if (pe.activeTopCount > 0 || pe.hadActiveTop) {
+                        pw.print(" (active-top)");
+                    }
+                    pw.println();
+                }
+            }
+        }
+    }
+
+    void rebatchIfNeeded(long now) {
+        long totalTime = mCurDataSet.getTotalTime(now);
+        if (totalTime > BATCHING_TIME) {
+            DataSet last = mCurDataSet;
+            last.mSummedTime = totalTime;
+            mCurDataSet = new DataSet();
+            last.finish(mCurDataSet, now);
+            System.arraycopy(mLastDataSets, 0, mLastDataSets, 1, mLastDataSets.length-1);
+            mLastDataSets[0] = last;
+        }
+    }
+
+    public void notePending(JobStatus job) {
+        final long now = SystemClock.uptimeMillis();
+        rebatchIfNeeded(now);
+        mCurDataSet.incPending(job.getSourceUid(), job.getSourcePackageName(), now);
+    }
+
+    public void noteNonpending(JobStatus job) {
+        final long now = SystemClock.uptimeMillis();
+        mCurDataSet.decPending(job.getSourceUid(), job.getSourcePackageName(), now);
+        rebatchIfNeeded(now);
+    }
+
+    public void noteActive(JobStatus job) {
+        final long now = SystemClock.uptimeMillis();
+        rebatchIfNeeded(now);
+        if (job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
+            mCurDataSet.incActiveTop(job.getSourceUid(), job.getSourcePackageName(), now);
+        } else {
+            mCurDataSet.incActive(job.getSourceUid(), job.getSourcePackageName(), now);
+        }
+    }
+
+    public void noteInactive(JobStatus job) {
+        final long now = SystemClock.uptimeMillis();
+        if (job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
+            mCurDataSet.decActiveTop(job.getSourceUid(), job.getSourcePackageName(), now);
+        } else {
+            mCurDataSet.decActive(job.getSourceUid(), job.getSourcePackageName(), now);
+        }
+        rebatchIfNeeded(now);
+    }
+
+    public float getLoadFactor(JobStatus job) {
+        final int uid = job.getSourceUid();
+        final String pkg = job.getSourcePackageName();
+        PackageEntry cur = mCurDataSet.getEntry(uid, pkg);
+        PackageEntry last = mLastDataSets[0] != null ? mLastDataSets[0].getEntry(uid, pkg) : null;
+        if (cur == null && last == null) {
+            return 0;
+        }
+        final long now = SystemClock.uptimeMillis();
+        long time = cur.getActiveTime(now) + cur.getPendingTime(now);
+        long period = mCurDataSet.getTotalTime(now);
+        if (last != null) {
+            time += last.getActiveTime(now) + last.getPendingTime(now);
+            period += mLastDataSets[0].getTotalTime(now);
+        }
+        return time / (float)period;
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        final long now = SystemClock.uptimeMillis();
+        final long nowEllapsed = SystemClock.elapsedRealtime();
+        final DataSet total;
+        if (mLastDataSets[0] != null) {
+            total = new DataSet(mLastDataSets[0]);
+            mLastDataSets[0].addTo(total, now);
+        } else {
+            total = new DataSet(mCurDataSet);
+        }
+        mCurDataSet.addTo(total, now);
+        for (int i = 1; i < mLastDataSets.length; i++) {
+            if (mLastDataSets[i] != null) {
+                mLastDataSets[i].dump(pw, "Historical stats", prefix, now, nowEllapsed);
+                pw.println();
+            }
+        }
+        total.dump(pw, "Current stats", prefix, now, nowEllapsed);
+    }
+}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index b235002..c4a2c731 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -93,16 +93,24 @@
     public static final boolean DEBUG = false;
 
     /** The maximum number of concurrent jobs we run at one time. */
-    private static final int MAX_JOB_CONTEXTS_COUNT = 8;
+    private static final int MAX_JOB_CONTEXTS_COUNT = 12;
+    /** The number of MAX_JOB_CONTEXTS_COUNT we reserve for the foreground app. */
+    private static final int FG_JOB_CONTEXTS_COUNT = 4;
     /** Enforce a per-app limit on scheduled jobs? */
     private static final boolean ENFORCE_MAX_JOBS = true;
     /** The maximum number of jobs that we allow an unprivileged app to schedule */
     private static final int MAX_JOBS_PER_APP = 100;
+    /** This is the job execution factor that is considered to be heavy use of the system. */
+    private static final float HEAVY_USE_FACTOR = .9f;
+    /** This is the job execution factor that is considered to be moderate use of the system. */
+    private static final float MODERATE_USE_FACTOR = .5f;
 
     /** Global local for all job scheduler state. */
     final Object mLock = new Object();
     /** Master list of jobs. */
     final JobStore mJobs;
+    /** Tracking amount of time each package runs for. */
+    final JobPackageTracker mJobPackageTracker = new JobPackageTracker();
 
     static final int MSG_JOB_EXPIRED = 0;
     static final int MSG_CHECK_JOB = 1;
@@ -173,7 +181,7 @@
      * Current limit on the number of concurrent JobServiceContext entries we want to
      * keep actively running a job.
      */
-    int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+    int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT;
 
     /**
      * Which uids are currently in the foreground.
@@ -386,7 +394,9 @@
         stopTrackingJob(cancelled, incomingJob, true /* writeBack */);
         synchronized (mLock) {
             // Remove from pending queue.
-            mPendingJobs.remove(cancelled);
+            if (mPendingJobs.remove(cancelled)) {
+                mJobPackageTracker.noteNonpending(cancelled);
+            }
             // Cancel if running.
             stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED);
             reportActive();
@@ -518,7 +528,7 @@
                 // Create the "runners".
                 for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
                     mActiveServices.add(
-                            new JobServiceContext(this, mBatteryStats,
+                            new JobServiceContext(this, mBatteryStats, mJobPackageTracker,
                                     getContext().getMainLooper()));
                 }
                 // Attach jobs to their controllers.
@@ -604,6 +614,20 @@
         return false;
     }
 
+    void noteJobsPending(List<JobStatus> jobs) {
+        for (int i = jobs.size() - 1; i >= 0; i--) {
+            JobStatus job = jobs.get(i);
+            mJobPackageTracker.notePending(job);
+        }
+    }
+
+    void noteJobsNonpending(List<JobStatus> jobs) {
+        for (int i = jobs.size() - 1; i >= 0; i--) {
+            JobStatus job = jobs.get(i);
+            mJobPackageTracker.noteNonpending(job);
+        }
+    }
+
     /**
      * Reschedules the given job based on the job's backoff policy. It doesn't make sense to
      * specify an override deadline on a failed job (the failed job will run even though it's not
@@ -759,6 +783,7 @@
                         // state is such that all ready jobs should be run immediately.
                         if (runNow != null && !mPendingJobs.contains(runNow)
                                 && mJobs.containsJob(runNow)) {
+                            mJobPackageTracker.notePending(runNow);
                             mPendingJobs.add(runNow);
                         }
                         queueReadyJobsForExecutionLockedH();
@@ -797,6 +822,7 @@
             if (DEBUG) {
                 Slog.d(TAG, "queuing all ready jobs for execution:");
             }
+            noteJobsNonpending(mPendingJobs);
             mPendingJobs.clear();
             mJobs.forEachJob(mReadyQueueFunctor);
             mReadyQueueFunctor.postProcess();
@@ -832,6 +858,7 @@
 
             public void postProcess() {
                 if (newReadyJobs != null) {
+                    noteJobsPending(newReadyJobs);
                     mPendingJobs.addAll(newReadyJobs);
                 }
                 newReadyJobs = null;
@@ -910,6 +937,7 @@
                     if (DEBUG) {
                         Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs.");
                     }
+                    noteJobsPending(runnableJobs);
                     mPendingJobs.addAll(runnableJobs);
                 } else {
                     if (DEBUG) {
@@ -935,6 +963,7 @@
         private void maybeQueueReadyJobsForExecutionLockedH() {
             if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");
 
+            noteJobsNonpending(mPendingJobs);
             mPendingJobs.clear();
             mJobs.forEachJob(mMaybeQueueFunctor);
             mMaybeQueueFunctor.postProcess();
@@ -998,16 +1027,28 @@
         }
     }
 
+    private int adjustJobPriority(int curPriority, JobStatus job) {
+        if (curPriority < JobInfo.PRIORITY_TOP_APP) {
+            float factor = mJobPackageTracker.getLoadFactor(job);
+            if (factor >= HEAVY_USE_FACTOR) {
+                curPriority += JobInfo.PRIORITY_ADJ_ALWAYS_RUNNING;
+            } else if (factor >= MODERATE_USE_FACTOR) {
+                curPriority += JobInfo.PRIORITY_ADJ_OFTEN_RUNNING;
+            }
+        }
+        return curPriority;
+    }
+
     private int evaluateJobPriorityLocked(JobStatus job) {
         int priority = job.getPriority();
         if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) {
-            return priority;
+            return adjustJobPriority(priority, job);
         }
         int override = mUidPriorityOverride.get(job.getSourceUid(), 0);
         if (override != 0) {
-            return override;
+            return adjustJobPriority(override, job);
         }
-        return priority;
+        return adjustJobPriority(priority, job);
     }
 
     /**
@@ -1029,16 +1070,16 @@
         }
         switch (memLevel) {
             case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
-                mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - 2) * 2) / 3;
+                mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT) * 2) / 3;
                 break;
             case ProcessStats.ADJ_MEM_FACTOR_LOW:
-                mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - 2) / 3;
+                mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT) / 3;
                 break;
             case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
                 mMaxActiveJobs = 1;
                 break;
             default:
-                mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+                mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT;
                 break;
         }
 
@@ -1134,7 +1175,9 @@
                     if (!mActiveServices.get(i).executeRunnableJob(pendingJob)) {
                         Slog.d(TAG, "Error executing " + pendingJob);
                     }
-                    mPendingJobs.remove(pendingJob);
+                    if (mPendingJobs.remove(pendingJob)) {
+                        mJobPackageTracker.noteNonpending(pendingJob);
+                    }
                 }
             }
             if (!preservePreferredUid) {
@@ -1444,6 +1487,8 @@
                 pw.print(": "); pw.println(mUidPriorityOverride.valueAt(i));
             }
             pw.println();
+            mJobPackageTracker.dump(pw, "");
+            pw.println();
             pw.println("Pending queue:");
             for (int i=0; i<mPendingJobs.size(); i++) {
                 JobStatus job = mPendingJobs.get(i);
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 4239248..4fd1350 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -105,6 +105,7 @@
     private final Context mContext;
     private final Object mLock;
     private final IBatteryStats mBatteryStats;
+    private final JobPackageTracker mJobPackageTracker;
     private PowerManager.WakeLock mWakeLock;
 
     // Execution state.
@@ -136,16 +137,18 @@
     /** Track when job will timeout. */
     private long mTimeoutElapsed;
 
-    JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats, Looper looper) {
-        this(service.getContext(), service.getLock(), batteryStats, service, looper);
+    JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats,
+            JobPackageTracker tracker, Looper looper) {
+        this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper);
     }
 
     @VisibleForTesting
     JobServiceContext(Context context, Object lock, IBatteryStats batteryStats,
-                      JobCompletedListener completedListener, Looper looper) {
+            JobPackageTracker tracker, JobCompletedListener completedListener, Looper looper) {
         mContext = context;
         mLock = lock;
         mBatteryStats = batteryStats;
+        mJobPackageTracker = tracker;
         mCallbackHandler = new JobServiceHandler(looper);
         mCompletedListener = completedListener;
         mAvailable = true;
@@ -208,6 +211,7 @@
             } catch (RemoteException e) {
                 // Whatever.
             }
+            mJobPackageTracker.noteActive(job);
             mAvailable = false;
             return true;
         }
@@ -580,6 +584,7 @@
                     return;
                 }
                 completedJob = mRunningJob;
+                mJobPackageTracker.noteInactive(completedJob);
                 try {
                     mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(),
                             mRunningJob.getSourceUid());
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 92b59965..1fb260d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7085,9 +7085,6 @@
             pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
         }
 
-        UsageStatsManager usageMgr =
-                (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE);
-
         int curr = 0;
         int total = pkgs.size();
         for (PackageParser.Package pkg : pkgs) {
@@ -7100,13 +7097,6 @@
                 continue;
             }
 
-            if (!causeFirstBoot && usageMgr.isAppInactive(pkg.packageName)) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Skipping update of of idle app " + pkg.packageName);
-                }
-                continue;
-            }
-
             if (DEBUG_DEXOPT) {
                 Log.i(TAG, "Extracting app " + curr + " of " + total + ": " + pkg.packageName);
             }
diff --git a/services/core/java/com/android/server/pm/SELinuxMMAC.java b/services/core/java/com/android/server/pm/SELinuxMMAC.java
index aa10c08..a6350fe 100644
--- a/services/core/java/com/android/server/pm/SELinuxMMAC.java
+++ b/services/core/java/com/android/server/pm/SELinuxMMAC.java
@@ -92,7 +92,7 @@
      * MAC_PERMISSIONS class variable which is set at class load time which itself
      * is based on the USE_OVERRIDE_POLICY class variable. For further guidance on
      * the proper structure of a mac_permissions.xml file consult the source code
-     * located at external/sepolicy/mac_permissions.xml.
+     * located at system/sepolicy/mac_permissions.xml.
      *
      * @return boolean indicating if policy was correctly loaded. A value of false
      *         typically indicates a structural problem with the xml or incorrectly
@@ -373,7 +373,7 @@
  * {@link Policy#getMatchedSeinfo} method. To create an instance of this use the
  * {@link PolicyBuilder} pattern class, where each instance is validated against a set
  * of invariants before being built and returned. Each instance can be guaranteed to
- * hold one valid policy stanza as outlined in the external/sepolicy/mac_permissions.xml
+ * hold one valid policy stanza as outlined in the system/sepolicy/mac_permissions.xml
  * file.
  * <p>
  * The following is an example of how to use {@link Policy.PolicyBuilder} to create a
@@ -519,7 +519,7 @@
      * A nested builder class to create {@link Policy} instances. A {@link Policy}
      * class instance represents one valid policy stanza found in a mac_permissions.xml
      * file. A valid policy stanza is defined to be a signer stanza which obeys the rules
-     * outlined in external/sepolicy/mac_permissions.xml. The {@link #build} method
+     * outlined in system/sepolicy/mac_permissions.xml. The {@link #build} method
      * ensures a set of invariants are upheld enforcing the correct stanza structure
      * before returning a valid Policy object.
      */
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index 27077f2..553c5de 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -80,8 +80,6 @@
                 .getInteger(R.integer.config_immersive_mode_confirmation_panic);
         mWindowManager = (WindowManager)
                 mContext.getSystemService(Context.WINDOW_SERVICE);
-        mVrManager = (IVrManager) IVrManager.Stub.asInterface(
-                ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE));
     }
 
     private long getNavBarExitDuration() {
@@ -121,11 +119,18 @@
 
     private boolean getVrMode() {
         boolean vrMode = false;
-        try {
-            vrMode = mVrManager.getVrModeState();
-        } catch (RemoteException ex) { }
+        if (mVrManager == null) {
+            // lazily grab this service since it may not be available at construction time
+            mVrManager = (IVrManager) IVrManager.Stub.asInterface(
+                ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE));
+        }
+        if (mVrManager != null) {
+            try {
+                vrMode = mVrManager.getVrModeState();
+            } catch (RemoteException ex) { }
+        }
         return vrMode;
-    }        
+    }
 
     public void immersiveModeChanged(String pkg, boolean isImmersiveMode,
             boolean userSetupComplete) {
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index df5d027..e17ea49 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -245,8 +245,16 @@
                     synchronized(mLock) {
                         try {
                             newPackage = findPreferredWebViewPackage();
-                            if (mCurrentWebViewPackage != null)
+                            if (mCurrentWebViewPackage != null) {
                                 oldProviderName = mCurrentWebViewPackage.packageName;
+                                if (changedState == WebViewUpdateService.PACKAGE_CHANGED
+                                        && newPackage.packageName.equals(oldProviderName)) {
+                                    // If we don't change package name we should only rerun the
+                                    // preparation phase if the current package has been replaced
+                                    // (not if it has been enabled/disabled).
+                                    return;
+                                }
+                            }
                             // Only trigger update actions if the updated package is the one
                             // that will be used, or the one that was in use before the
                             // update, or if we haven't seen a valid WebView package before.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 57f38d1..9088522 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.animation.ValueAnimator;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
@@ -153,6 +154,8 @@
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.Socket;
 import java.text.DateFormat;
 import java.util.ArrayList;
@@ -332,6 +335,14 @@
 
     private static final String PROPERTY_BUILD_DATE_UTC = "ro.build.date.utc";
 
+    // Enums for animation scale update types.
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({WINDOW_ANIMATION_SCALE, TRANSITION_ANIMATION_SCALE, ANIMATION_DURATION_SCALE})
+    private @interface UpdateAnimationScaleMode {};
+    private static final int WINDOW_ANIMATION_SCALE = 0;
+    private static final int TRANSITION_ANIMATION_SCALE = 1;
+    private static final int ANIMATION_DURATION_SCALE = 2;
+
     final private KeyguardDisableHandler mKeyguardDisableHandler;
 
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -613,18 +624,42 @@
     private final class SettingsObserver extends ContentObserver {
         private final Uri mDisplayInversionEnabledUri =
                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+        private final Uri mWindowAnimationScaleUri =
+                Settings.Global.getUriFor(Settings.Global.WINDOW_ANIMATION_SCALE);
+        private final Uri mTransitionAnimationScaleUri =
+                Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE);
+        private final Uri mAnimationDurationScaleUri =
+                Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE);
 
         public SettingsObserver() {
             super(new Handler());
             ContentResolver resolver = mContext.getContentResolver();
             resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(mWindowAnimationScaleUri, false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(mTransitionAnimationScaleUri, false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(mAnimationDurationScaleUri, false, this,
+                    UserHandle.USER_ALL);
         }
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             if (mDisplayInversionEnabledUri.equals(uri)) {
                 updateCircularDisplayMaskIfNeeded();
+            } else {
+                @UpdateAnimationScaleMode
+                final int mode;
+                if (uri.equals(mWindowAnimationScaleUri)) {
+                    mode = WINDOW_ANIMATION_SCALE;
+                } else if (uri.equals(mTransitionAnimationScaleUri)) {
+                    mode = TRANSITION_ANIMATION_SCALE;
+                } else { // uri.equals(mAnimationDurationScaleUri)
+                    mode = ANIMATION_DURATION_SCALE;
+                }
+                Message m = mH.obtainMessage(H.UPDATE_ANIMATION_SCALE, mode, 0);
+                mH.sendMessage(m);
             }
         }
     }
@@ -3905,16 +3940,6 @@
                 return;
             }
 
-            if (transferStartingWindow(transferFrom, wtoken)) {
-                return;
-            }
-
-            // There is no existing starting window, and the caller doesn't
-            // want us to create one, so that's it!
-            if (!createIfNeeded) {
-                return;
-            }
-
             // If this is a translucent window, then don't
             // show a starting window -- the current effect (a full-screen
             // opaque starting window that fades away to the real contents
@@ -3960,6 +3985,16 @@
                 }
             }
 
+            if (transferStartingWindow(transferFrom, wtoken)) {
+                return;
+            }
+
+            // There is no existing starting window, and the caller doesn't
+            // want us to create one, so that's it!
+            if (!createIfNeeded) {
+                return;
+            }
+
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
             wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
                     labelRes, icon, logo, windowFlags);
@@ -7748,6 +7783,8 @@
         public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
         public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
 
+        public static final int UPDATE_ANIMATION_SCALE = 51;
+
         /**
          * Used to denote that an integer field in a message will not be used.
          */
@@ -8030,6 +8067,36 @@
                     break;
                 }
 
+                case UPDATE_ANIMATION_SCALE: {
+                    @UpdateAnimationScaleMode
+                    final int mode = msg.arg1;
+                    switch (mode) {
+                        case WINDOW_ANIMATION_SCALE: {
+                            mWindowAnimationScaleSetting = Settings.Global.getFloat(
+                                    mContext.getContentResolver(),
+                                    Settings.Global.WINDOW_ANIMATION_SCALE,
+                                    mWindowAnimationScaleSetting);
+                            break;
+                        }
+                        case TRANSITION_ANIMATION_SCALE: {
+                            mTransitionAnimationScaleSetting = Settings.Global.getFloat(
+                                    mContext.getContentResolver(),
+                                    Settings.Global.TRANSITION_ANIMATION_SCALE,
+                                    mTransitionAnimationScaleSetting);
+                            break;
+                        }
+                        case ANIMATION_DURATION_SCALE: {
+                            mAnimatorDurationScaleSetting = Settings.Global.getFloat(
+                                    mContext.getContentResolver(),
+                                    Settings.Global.ANIMATOR_DURATION_SCALE,
+                                    mAnimatorDurationScaleSetting);
+                            dispatchNewAnimatorScaleLocked(null);
+                            break;
+                        }
+                    }
+                    break;
+                }
+
                 case FORCE_GC: {
                     synchronized (mWindowMap) {
                         // Since we're holding both mWindowMap and mAnimator we don't need to
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c48d7d1..8371cfe 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2410,8 +2410,8 @@
             pw.print(prefix); pw.print("mToken="); pw.println(mToken);
             pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
             if (mAppToken != null) {
-                pw.print(prefix); pw.print("mAppToken="); pw.print(mAppToken);
-                pw.print(" isAnimatingWithSavedSurface()=");
+                pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
+                pw.print(prefix); pw.print(" isAnimatingWithSavedSurface()=");
                 pw.print(isAnimatingWithSavedSurface());
                 pw.print(" mAppDied=");pw.println(mAppDied);
             }
@@ -2496,6 +2496,7 @@
                     pw.print(" content="); mContentInsets.printShortString(pw);
                     pw.print(" visible="); mVisibleInsets.printShortString(pw);
                     pw.print(" stable="); mStableInsets.printShortString(pw);
+                    pw.print(" surface="); mAttrs.surfaceInsets.printShortString(pw);
                     pw.print(" outsets="); mOutsets.printShortString(pw);
                     pw.println();
             pw.print(prefix); pw.print("Lst insets: overscan=");
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 140f381..0245513 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.StackId;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
@@ -1032,7 +1033,7 @@
                         // relative to their containing frame. We need to offset the difference
                         // between the containing frame as used to calculate the crop and our
                         // bounds to compensate for this.
-                        if (mWin.isChildWindow() && mWin.layoutInParentFrame()) {
+                        if (mWin.layoutInParentFrame()) {
                             mClipRect.offset( (mWin.mContainingFrame.left - mWin.mFrame.left),
                                     mWin.mContainingFrame.top - mWin.mFrame.top );
                         }
@@ -1164,8 +1165,8 @@
             final float scale = w.mInvGlobalScale;
             mSystemDecorRect.left = (int) (mSystemDecorRect.left * scale - 0.5f);
             mSystemDecorRect.top = (int) (mSystemDecorRect.top * scale - 0.5f);
-            mSystemDecorRect.right = (int) ((mSystemDecorRect.right+1) * scale - 0.5f);
-            mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom+1) * scale - 0.5f);
+            mSystemDecorRect.right = (int) ((mSystemDecorRect.right + 1) * scale - 0.5f);
+            mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom + 1) * scale - 0.5f);
         }
     }
 
@@ -1178,8 +1179,8 @@
             return;
         }
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop for window: " + w + ", " + "mLastCrop=" +
-                mLastClipRect);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG,
+                "Updating crop win=" + w + " mLastCrop=" + mLastClipRect);
 
         // Need to recompute a new system decor rect each time.
         if (!w.isDefaultDisplay()) {
@@ -1204,8 +1205,8 @@
         } else {
             // Crop to the system decor specified by policy.
             calculateSystemDecorRect();
-            if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop for " + w + ", mDecorFrame="
-                    + w.mDecorFrame + ", mSystemDecorRect=" + mSystemDecorRect);
+            if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
+                    + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
         }
 
         final boolean fullscreen = w.isFrameFullscreen(displayInfo);
@@ -1215,8 +1216,8 @@
         // We use the clip rect as provided by the tranformation for non-fullscreen windows to
         // avoid premature clipping with the system decor rect.
         clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : mSystemDecorRect);
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Initial clip rect: " + clipRect + ", mHasClipRect="
-                + mHasClipRect + ", fullscreen=" + fullscreen);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
+                + " mHasClipRect=" + mHasClipRect + " fullscreen=" + fullscreen);
 
         if (isFreeformResizing && !w.isChildWindow()) {
             // For freeform resizing non child windows, we are using the big surface positioned
@@ -1243,7 +1244,8 @@
 
         finalClipRect.setEmpty();
         adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing);
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + clipRect);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG,
+                "win=" + w + " Clip rect after stack adjustment=" + clipRect);
 
         w.transformFromScreenToSurfaceSpace(clipRect);
 
@@ -1254,6 +1256,8 @@
     }
 
     void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin
+                + " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
         if (!clipRect.equals(mLastClipRect)) {
             mLastClipRect.set(clipRect);
             mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
@@ -1294,13 +1298,14 @@
 
         final TaskStack stack = task.mStack;
         stack.getDimBounds(mTmpStackBounds);
+        final Rect surfaceInsets = w.getAttrs().surfaceInsets;
         // When we resize we use the big surface approach, which means we can't trust the
         // window frame bounds anymore. Instead, the window will be placed at 0, 0, but to avoid
         // hardcoding it, we use surface coordinates.
         final int frameX = isFreeformResizing ? (int) mSurfaceController.getX() :
-                w.mFrame.left + mWin.mXOffset - w.getAttrs().surfaceInsets.left;
+                w.mFrame.left + mWin.mXOffset - surfaceInsets.left;
         final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
-                w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;
+                w.mFrame.top + mWin.mYOffset - surfaceInsets.top;
 
         // If we are animating, we either apply the clip before applying all the animation
         // transformation or after all the transformation.
@@ -1311,6 +1316,15 @@
         if (useFinalClipRect) {
             finalClipRect.set(mTmpStackBounds);
         } else {
+            if (StackId.hasWindowShadow(stack.mStackId)
+                    && !StackId.isTaskResizeAllowed(stack.mStackId)) {
+                // The windows in this stack display drop shadows and the fill the entire stack
+                // area. Adjust the stack bounds we will use to cropping take into account the
+                // offsets we use to display the drop shadow so it doesn't get cropped.
+                mTmpStackBounds.inset(-surfaceInsets.left, -surfaceInsets.top,
+                        -surfaceInsets.right, -surfaceInsets.bottom);
+            }
+
             clipRect.left = Math.max(0,
                     Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
             clipRect.top = Math.max(0,
@@ -1356,21 +1370,19 @@
             // past where the system would have cropped us
             mTmpClipRect.set(0, 0, mTmpSize.width(), mTmpSize.height());
             mTmpFinalClipRect.setEmpty();
-            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
         } else {
             mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
                     recoveringMemory);
-            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
         }
 
+        updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
 
         mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * extraHScale,
                 mDtDx * w.mVScale * extraVScale,
                 mDsDy * w.mHScale * extraHScale,
                 mDtDy * w.mVScale * extraVScale, recoveringMemory);
         mSurfaceResized = mSurfaceController.setSizeInTransaction(
-                mTmpSize.width(), mTmpSize.height(),
-                recoveringMemory);
+                mTmpSize.width(), mTmpSize.height(), recoveringMemory);
 
         if (mSurfaceResized) {
             mReportSurfaceResized = true;
@@ -1775,7 +1787,7 @@
             pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
                     pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
                     pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
-                    pw.print(" mAnimation="); pw.println(mAnimation);
+                    pw.print(" mAnimation="); pw.print(mAnimation);
                     pw.print(" mStackClip="); pw.println(mStackClip);
         }
         if (mHasTransformation || mHasLocalTransformation) {
@@ -1793,9 +1805,9 @@
             pw.print(prefix); pw.print(" mLastHidden="); pw.println(mLastHidden);
             pw.print(prefix); pw.print("mSystemDecorRect="); mSystemDecorRect.printShortString(pw);
             pw.print(" last="); mLastSystemDecorRect.printShortString(pw);
-            if (mHasClipRect) {
-                pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
-            }
+            pw.print(" mHasClipRect="); pw.print(mHasClipRect);
+            pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
+
             if (!mLastFinalClipRect.isEmpty()) {
                 pw.print(" mLastFinalClipRect="); mLastFinalClipRect.printShortString(pw);
             }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 72e8bd3..0454b00 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8660,7 +8660,7 @@
     }
 
     @Override
-    public void setOrganizationName(@NonNull ComponentName who, String text) {
+    public void setOrganizationName(@NonNull ComponentName who, CharSequence text) {
         if (!mHasFeature) {
             return;
         }
@@ -8671,14 +8671,15 @@
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (!TextUtils.equals(admin.organizationName, text)) {
-                admin.organizationName = TextUtils.nullIfEmpty(text);
+                admin.organizationName = (text == null || text.length() == 0)
+                        ? null : text.toString();
                 saveSettingsLocked(userHandle);
             }
         }
     }
 
     @Override
-    public String getOrganizationName(@NonNull ComponentName who) {
+    public CharSequence getOrganizationName(@NonNull ComponentName who) {
         if (!mHasFeature) {
             return null;
         }
@@ -8692,7 +8693,7 @@
     }
 
     @Override
-    public String getOrganizationNameForUser(int userHandle) {
+    public CharSequence getOrganizationNameForUser(int userHandle) {
         if (!mHasFeature) {
             return null;
         }
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index 005a483..c1f0038 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -37,6 +37,8 @@
         final int parentLeft, parentTop;
         final Matrix matrix;
         final String className;
+        final float textSize;
+        final int textColor;
         final CharSequence text;
         final int scrollY;
         final int[] lineCharOffsets;
@@ -50,6 +52,8 @@
             this.parentTop = parentTop;
             this.matrix = new Matrix(matrix);
             this.className = node.getClassName();
+            this.textSize = node.getTextSize();
+            this.textColor = node.getTextColor();
             this.text = node.getText() != null ? node.getText() : node.getContentDescription();
             this.scrollY = node.getScrollY();
             this.lineCharOffsets = node.getTextLineCharOffsets();
@@ -113,7 +117,9 @@
             TextEntry te = mTextRects.get(i);
             Log.d(TAG, "View " + te.className + " " + te.bounds.toShortString()
                     + " in " + te.parentLeft + "," + te.parentTop
-                    + " matrix=" + te.matrix.toShortString() + ": "
+                    + " matrix=" + te.matrix.toShortString()
+                    + " size=" + te.textSize + " color=#" + Integer.toHexString(te.textColor)
+                    + ": "
                     + te.text);
             if (te.lineCharOffsets != null && te.lineBaselines != null) {
                 final int num = te.lineCharOffsets.length < te.lineBaselines.length
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index f8c1ea3..1a8197c 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -687,7 +687,7 @@
         Bundle scanParams = new Bundle();
         scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
         scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
-        sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
+        mAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
     }
 
     /**
@@ -700,7 +700,7 @@
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
+        mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
     }
     /**
      * reports currently available scan results on appropriate listeners
@@ -708,7 +708,7 @@
      */
     public boolean getScanResults() {
         validateChannel();
-        Message reply = sAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
+        Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
         return reply.what == CMD_OP_SUCCEEDED;
     }
 
@@ -741,7 +741,7 @@
         Bundle scanParams = new Bundle();
         scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
         scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
-        sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
+        mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
     }
 
     /**
@@ -754,7 +754,7 @@
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
+        mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
     }
 
     private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
@@ -764,7 +764,7 @@
         scanSettings.isPnoScan = true;
         pnoParams.putParcelable(PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
         pnoParams.putParcelable(PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings);
-        sAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
+        mAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
     }
     /**
      * Start wifi connected PNO scan
@@ -820,7 +820,7 @@
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key);
+        mAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key);
     }
 
     /** specifies information about an access point of interest */
@@ -956,7 +956,7 @@
         int key = addListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
+        mAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
     }
 
     /**
@@ -968,14 +968,14 @@
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
+        mAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
     }
 
     /** @hide */
     @SystemApi
     public void configureWifiChange(WifiChangeSettings settings) {
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+        mAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
     }
 
     /** interface to receive hotlist events on; use this on {@link #setHotlist} */
@@ -1060,7 +1060,7 @@
         HotlistSettings settings = new HotlistSettings();
         settings.bssidInfos = bssidInfos;
         settings.apLostThreshold = apLostThreshold;
-        sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
+        mAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
     }
 
     /**
@@ -1072,7 +1072,7 @@
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
+        mAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
     }
 
 
@@ -1137,17 +1137,14 @@
     private IWifiScanner mService;
 
     private static final int INVALID_KEY = 0;
-    private static int sListenerKey = 1;
+    private int mListenerKey = 1;
 
-    private static final SparseArray sListenerMap = new SparseArray();
-    private static final Object sListenerMapLock = new Object();
+    private final SparseArray mListenerMap = new SparseArray();
+    private final Object mListenerMapLock = new Object();
 
-    private static AsyncChannel sAsyncChannel;
-    private static CountDownLatch sConnected;
-
-    private static final Object sThreadRefLock = new Object();
-    private static int sThreadRefCount;
-    private static Handler sInternalHandler;
+    private AsyncChannel mAsyncChannel;
+    private final CountDownLatch mConnected;
+    private final Handler mInternalHandler;
 
     /**
      * Create a new WifiScanner instance.
@@ -1156,10 +1153,11 @@
      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
      * @param context the application context
      * @param service the Binder interface
+     * @param looper the Looper used to deliver callbacks
      * @hide
      */
-    public WifiScanner(Context context, IWifiScanner service) {
-        this(context, service, null, true);
+    public WifiScanner(Context context, IWifiScanner service, Looper looper) {
+        this(context, service, looper, true);
     }
 
     /**
@@ -1167,8 +1165,7 @@
      *
      * @param context The application context.
      * @param service The IWifiScanner Binder interface
-     * @param looper Looper for running WifiScanner operations. If null, a handler thread will be
-     *          created for running WifiScanner operations.
+     * @param looper the Looper used to deliver callbacks
      * @param waitForConnection If true, this will not return until a connection to Wifi Scanner
      *          service is established.
      * @hide
@@ -1178,50 +1175,34 @@
             boolean waitForConnection) {
         mContext = context;
         mService = service;
-        init(looper, waitForConnection);
-    }
 
-    private void init(Looper looper, boolean waitForConnection) {
-        synchronized (sThreadRefLock) {
-            if (++sThreadRefCount == 1) {
-                Messenger messenger = null;
-                try {
-                    messenger = mService.getMessenger();
-                } catch (RemoteException e) {
-                    /* do nothing */
-                } catch (SecurityException e) {
-                    /* do nothing */
-                }
+        Messenger messenger = null;
+        try {
+            messenger = mService.getMessenger();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
 
-                if (messenger == null) {
-                    sAsyncChannel = null;
-                    return;
-                }
+        if (messenger == null) {
+            throw new IllegalStateException("getMessenger() returned null!  This is invalid.");
+        }
 
-                sAsyncChannel = new AsyncChannel();
-                sConnected = new CountDownLatch(1);
+        mAsyncChannel = new AsyncChannel();
+        mConnected = new CountDownLatch(1);
 
-                if (looper == null) {
-                    HandlerThread thread = new HandlerThread("WifiScanner");
-                    thread.start();
-                    sInternalHandler = new ServiceHandler(thread.getLooper());
-                } else {
-                    sInternalHandler = new ServiceHandler(looper);
-                }
-                sAsyncChannel.connect(mContext, sInternalHandler, messenger);
-                if (waitForConnection) {
-                    try {
-                        sConnected.await();
-                    } catch (InterruptedException e) {
-                        Log.e(TAG, "interrupted wait at init");
-                    }
-                }
+        mInternalHandler = new ServiceHandler(looper);
+        mAsyncChannel.connect(mContext, mInternalHandler, messenger);
+        if (waitForConnection) {
+            try {
+                mConnected.await();
+            } catch (InterruptedException e) {
+                Log.e(TAG, "interrupted wait at init");
             }
         }
     }
 
     private void validateChannel() {
-        if (sAsyncChannel == null) throw new IllegalStateException(
+        if (mAsyncChannel == null) throw new IllegalStateException(
                 "No permission to access and change wifi or a bad initialization");
     }
 
@@ -1229,7 +1210,7 @@
     // send an error message to internal handler; Otherwise add the listener to the listener map and
     // return the key of the listener.
     private int addListener(ActionListener listener) {
-        synchronized (sListenerMap) {
+        synchronized (mListenerMapLock) {
             boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
             // Note we need to put the listener into listener map even if it's a duplicate as the
             // internal handler will need the key to find the listener. In case of duplicates,
@@ -1239,7 +1220,7 @@
                 if (DBG) Log.d(TAG, "listener key already exists");
                 OperationResult operationResult = new OperationResult(REASON_DUPLICATE_REQEUST,
                         "Outstanding request with same key not stopped yet");
-                Message message = Message.obtain(sInternalHandler, CMD_OP_FAILED, 0, key,
+                Message message = Message.obtain(mInternalHandler, CMD_OP_FAILED, 0, key,
                         operationResult);
                 message.sendToTarget();
                 return INVALID_KEY;
@@ -1249,55 +1230,55 @@
         }
     }
 
-    private static int putListener(Object listener) {
+    private int putListener(Object listener) {
         if (listener == null) return INVALID_KEY;
         int key;
-        synchronized (sListenerMapLock) {
+        synchronized (mListenerMapLock) {
             do {
-                key = sListenerKey++;
+                key = mListenerKey++;
             } while (key == INVALID_KEY);
-            sListenerMap.put(key, listener);
+            mListenerMap.put(key, listener);
         }
         return key;
     }
 
-    private static Object getListener(int key) {
+    private Object getListener(int key) {
         if (key == INVALID_KEY) return null;
-        synchronized (sListenerMapLock) {
-            Object listener = sListenerMap.get(key);
+        synchronized (mListenerMapLock) {
+            Object listener = mListenerMap.get(key);
             return listener;
         }
     }
 
-    private static int getListenerKey(Object listener) {
+    private int getListenerKey(Object listener) {
         if (listener == null) return INVALID_KEY;
-        synchronized (sListenerMapLock) {
-            int index = sListenerMap.indexOfValue(listener);
+        synchronized (mListenerMapLock) {
+            int index = mListenerMap.indexOfValue(listener);
             if (index == -1) {
                 return INVALID_KEY;
             } else {
-                return sListenerMap.keyAt(index);
+                return mListenerMap.keyAt(index);
             }
         }
     }
 
-    private static Object removeListener(int key) {
+    private Object removeListener(int key) {
         if (key == INVALID_KEY) return null;
-        synchronized (sListenerMapLock) {
-            Object listener = sListenerMap.get(key);
-            sListenerMap.remove(key);
+        synchronized (mListenerMapLock) {
+            Object listener = mListenerMap.get(key);
+            mListenerMap.remove(key);
             return listener;
         }
     }
 
-    private static int removeListener(Object listener) {
+    private int removeListener(Object listener) {
         int key = getListenerKey(listener);
         if (key == INVALID_KEY) {
             Log.e(TAG, "listener cannot be found");
             return key;
         }
-        synchronized (sListenerMapLock) {
-            sListenerMap.remove(key);
+        synchronized (mListenerMapLock) {
+            mListenerMap.remove(key);
             return key;
         }
     }
@@ -1338,7 +1319,7 @@
                 };
     }
 
-    private static class ServiceHandler extends Handler {
+    private class ServiceHandler extends Handler {
         ServiceHandler(Looper looper) {
             super(looper);
         }
@@ -1347,14 +1328,14 @@
             switch (msg.what) {
                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                        sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+                        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
                     } else {
                         Log.e(TAG, "Failed to set up channel connection");
                         // This will cause all further async API calls on the WifiManager
                         // to fail and throw an exception
-                        sAsyncChannel = null;
+                        mAsyncChannel = null;
                     }
-                    sConnected.countDown();
+                    mConnected.countDown();
                     return;
                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
                     return;
@@ -1362,7 +1343,7 @@
                     Log.e(TAG, "Channel connection lost");
                     // This will cause all further async API calls on the WifiManager
                     // to fail and throw an exception
-                    sAsyncChannel = null;
+                    mAsyncChannel = null;
                     getLooper().quit();
                     return;
             }