Merge "zygote: Remove NativeLoader initialization step" into nyc-dev
diff --git a/Android.mk b/Android.mk
index 7d7aa48..2cfc9a2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -1142,50 +1142,54 @@
 LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
 LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
 # specify a second html input dir and an output path relative to OUT_DIR)
-LOCAL_ADDITIONAL_HTML_DIR:=docs/html-intl/intl /
+LOCAL_ADDITIONAL_HTML_DIR:=docs/html-intl /
 
 LOCAL_MODULE := ds
 
 LOCAL_DROIDDOC_OPTIONS:= \
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
 		-devsite \
+		-hdf devsite true \
 		-toroot / \
 		-hdf android.whichdoc online \
-		-hdf devsite true
+		$(sample_groups) \
+		-useUpdatedTemplates \
+		-hdf android.hasSamples true \
+		-samplesdir $(samples_dir)
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
 
 include $(BUILD_DROIDDOC)
 
-# ==== docs for the ndk =======================
+# ==== site updates for docs (on the androiddevdocs app engine server) =======================
 include $(CLEAR_VARS)
+
 LOCAL_SRC_FILES:=$(framework_docs_LOCAL_SRC_FILES)
 LOCAL_INTERMEDIATE_SOURCES:=$(framework_docs_LOCAL_INTERMEDIATE_SOURCES)
 LOCAL_STATIC_JAVA_LIBRARIES:=$(framework_docs_LOCAL_STATIC_JAVA_LIBRARIES)
 LOCAL_JAVA_LIBRARIES:=$(framework_docs_LOCAL_JAVA_LIBRARIES)
 LOCAL_MODULE_CLASS:=$(framework_docs_LOCAL_MODULE_CLASS)
 LOCAL_DROIDDOC_SOURCE_PATH:=$(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH)
-LOCAL_DROIDDOC_HTML_DIR:=docs/html-ndk
+LOCAL_DROIDDOC_HTML_DIR:=$(framework_docs_LOCAL_DROIDDOC_HTML_DIR)
 LOCAL_ADDITIONAL_JAVA_DIR:=$(framework_docs_LOCAL_ADDITIONAL_JAVA_DIR)
 LOCAL_ADDITIONAL_DEPENDENCIES:=$(framework_docs_LOCAL_ADDITIONAL_DEPENDENCIES)
-# specify a second html input dir and an output path relative to OUT_DIR)
-LOCAL_ADDITIONAL_HTML_DIR:=docs/html-intl/intl /
+LOCAL_ADDITIONAL_HTML_DIR:=docs/html-intl /
 
-LOCAL_MODULE := online-ndk
+LOCAL_MODULE := online-sdk-dev
 
 LOCAL_DROIDDOC_OPTIONS:= \
 		$(framework_docs_LOCAL_DROIDDOC_OPTIONS) \
 		-toroot / \
 		-hdf android.whichdoc online \
 		$(sample_groups) \
+		-useUpdatedTemplates \
 		-hdf android.hasSamples true \
 		-samplesdir $(samples_dir)
 
-LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk
+LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR:=build/tools/droiddoc/templates-sdk-dev
 
 include $(BUILD_DROIDDOC)
 
-
 # ==== docs that have all of the stuff that's @hidden =======================
 include $(CLEAR_VARS)
 
diff --git a/api/current.txt b/api/current.txt
index 4dfbe63..6fdd1bc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2699,7 +2699,7 @@
     method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler);
     method public float getCenterX();
     method public float getCenterY();
-    method public android.graphics.Region getMagnifiedRegion();
+    method public android.graphics.Region getMagnificationRegion();
     method public float getScale();
     method public boolean removeListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
     method public boolean reset(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 3344b52..41b73eb 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2810,7 +2810,7 @@
     method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler);
     method public float getCenterX();
     method public float getCenterY();
-    method public android.graphics.Region getMagnifiedRegion();
+    method public android.graphics.Region getMagnificationRegion();
     method public float getScale();
     method public boolean removeListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
     method public boolean reset(boolean);
diff --git a/api/test-current.txt b/api/test-current.txt
index a0ca0f4..d40d0b8 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2699,7 +2699,7 @@
     method public void addListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener, android.os.Handler);
     method public float getCenterX();
     method public float getCenterY();
-    method public android.graphics.Region getMagnifiedRegion();
+    method public android.graphics.Region getMagnificationRegion();
     method public float getScale();
     method public boolean removeListener(android.accessibilityservice.AccessibilityService.MagnificationController.OnMagnificationChangedListener);
     method public boolean reset(boolean);
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 56728ad..8b277b2 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -925,18 +925,25 @@
         }
 
         /**
-         * Returns the region of the screen currently being magnified. If
-         * magnification is not enabled, the returned region will be empty.
+         * Returns the region of the screen currently active for magnification. Changes to
+         * magnification scale and center only affect this portion of the screen. The rest of the
+         * screen, for example input methods, cannot be magnified. This region is relative to the
+         * unscaled screen and is independent of the scale and center point.
+         * <p>
+         * The returned region will be empty if magnification is not active. Magnification is active
+         * if magnification gestures are enabled or if a service is running that can control
+         * magnification.
          * <p>
          * <strong>Note:</strong> If the service is not yet connected (e.g.
          * {@link AccessibilityService#onServiceConnected()} has not yet been
          * called) or the service has been disconnected, this method will
          * return an empty region.
          *
-         * @return the screen-relative bounds of the magnified region
+         * @return the region of the screen currently active for magnification, or an empty region
+         * if magnification is not active.
          */
         @NonNull
-        public Region getMagnifiedRegion() {
+        public Region getMagnificationRegion() {
             final IAccessibilityServiceConnection connection =
                     AccessibilityInteractionClient.getInstance().getConnection(
                             mService.mConnectionId);
@@ -1049,11 +1056,12 @@
              * Called when the magnified region, scale, or center changes.
              *
              * @param controller the magnification controller
-             * @param region the new magnified region, may be empty if
-             *               magnification is not enabled (e.g. scale is 1)
+             * @param region the magnification region
              * @param scale the new scale
-             * @param centerX the new X coordinate around which magnification is focused
-             * @param centerY the new Y coordinate around which magnification is focused
+             * @param centerX the new X coordinate, in unscaled coordinates, around which
+             * magnification is focused
+             * @param centerY the new Y coordinate, in unscaled coordinates, around which
+             * magnification is focused
              */
             void onMagnificationChanged(@NonNull MagnificationController controller,
                     @NonNull Region region, float scale, float centerX, float centerY);
diff --git a/core/java/android/accessibilityservice/GestureDescription.java b/core/java/android/accessibilityservice/GestureDescription.java
index e18a34d..fc9581e 100644
--- a/core/java/android/accessibilityservice/GestureDescription.java
+++ b/core/java/android/accessibilityservice/GestureDescription.java
@@ -18,7 +18,6 @@
 
 import android.annotation.IntRange;
 import android.annotation.NonNull;
-import android.graphics.Matrix;
 import android.graphics.Path;
 import android.graphics.PathMeasure;
 import android.graphics.RectF;
@@ -26,10 +25,8 @@
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
-import android.view.ViewConfiguration;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.List;
 
 /**
@@ -160,9 +157,10 @@
         private final List<StrokeDescription> mStrokes = new ArrayList<>();
 
         /**
-         * Add a stroke to the gesture description. Up to {@code MAX_STROKE_COUNT} paths may be
-         * added to a gesture, and the total gesture duration (earliest path start time to latest path
-         * end time) may not exceed {@code MAX_GESTURE_DURATION_MS}.
+         * Add a stroke to the gesture description. Up to
+         * {@link GestureDescription#getMaxStrokeCount()} paths may be
+         * added to a gesture, and the total gesture duration (earliest path start time to latest
+         * path end time) may not exceed {@link GestureDescription#getMaxGestureDuration()}.
          *
          * @param strokeDescription the stroke to add.
          *
@@ -201,10 +199,13 @@
         long mEndTime;
         private float mTimeToLengthConversion;
         private PathMeasure mPathMeasure;
+        // The tap location is only set for zero-length paths
+        float[] mTapLocation;
 
         /**
-         * @param path The path to follow. Must have exactly one contour, and that contour must
-         * have nonzero length. The bounds of the path must not be negative.
+         * @param path The path to follow. Must have exactly one contour. The bounds of the path
+         * must not be negative. The path must not be empty. If the path has zero length
+         * (for example, a single {@code moveTo()}), the stroke is a touch that doesn't move.
          * @param startTime The time, in milliseconds, from the time the gesture starts to the
          * time the stroke should start. Must not be negative.
          * @param duration The duration, in milliseconds, the stroke takes to traverse the path.
@@ -225,10 +226,18 @@
                     || (bounds.left < 0)) {
                 throw new IllegalArgumentException("Path bounds must not be negative");
             }
+            if (path.isEmpty()) {
+                throw new IllegalArgumentException("Path is empty");
+            }
             mPath = new Path(path);
             mPathMeasure = new PathMeasure(path, false);
             if (mPathMeasure.getLength() == 0) {
-                throw new IllegalArgumentException("Path has zero length");
+                // Treat zero-length paths as taps
+                Path tempPath = new Path(path);
+                tempPath.lineTo(-1, -1);
+                mTapLocation = new float[2];
+                PathMeasure pathMeasure = new PathMeasure(tempPath, false);
+                pathMeasure.getPosTan(0, mTapLocation, null);
             }
             if (mPathMeasure.nextContour()) {
                 throw new IllegalArgumentException("Path has more than one contour");
@@ -237,12 +246,10 @@
              * Calling nextContour has moved mPathMeasure off the first contour, which is the only
              * one we care about. Set the path again to go back to the first contour.
              */
-            mPathMeasure.setPath(path, false);
+            mPathMeasure.setPath(mPath, false);
             mStartTime = startTime;
             mEndTime = startTime + duration;
-            if (duration > 0) {
-                mTimeToLengthConversion = getLength() / duration;
-            }
+            mTimeToLengthConversion = getLength() / duration;
         }
 
         /**
@@ -278,6 +285,11 @@
 
         /* Assumes hasPointForTime returns true */
         boolean getPosForTime(long time, float[] pos) {
+            if (mTapLocation != null) {
+                pos[0] = mTapLocation[0];
+                pos[1] = mTapLocation[1];
+                return true;
+            }
             if (time == mEndTime) {
                 // Close to the end time, roundoff can be a problem
                 return mPathMeasure.getPosTan(getLength(), pos, null);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0764ff4..f7c0b4c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -3479,7 +3479,9 @@
                     // the decor view we have to notify the view root that the
                     // callbacks may have changed.
                     ViewRootImpl impl = decor.getViewRootImpl();
-                    impl.notifyChildRebuilt();
+                    if (impl != null) {
+                        impl.notifyChildRebuilt();
+                    }
                 }
                 if (a.mVisibleFromClient && !a.mWindowAdded) {
                     a.mWindowAdded = true;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d7705b9..2a3e3d8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3351,7 +3351,8 @@
         }
 
         private void resetStandardTemplateWithActions(RemoteViews big) {
-            big.setViewVisibility(R.id.actions_container, View.GONE);
+            // actions_container is only reset when there are no actions to avoid focus issues with
+            // remote inputs.
             big.setViewVisibility(R.id.actions, View.GONE);
             big.removeAllViews(R.id.actions);
 
@@ -3396,6 +3397,8 @@
                     }
                     big.addView(R.id.actions, button);
                 }
+            } else {
+                big.setViewVisibility(R.id.actions_container, View.GONE);
             }
 
             CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
@@ -4265,15 +4268,19 @@
         public RemoteViews makeBigContentView() {
 
             // Nasty
-            CharSequence oldBuilderContentText =
-                    mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT);
+            CharSequence text = mBuilder.getAllExtras().getCharSequence(EXTRA_TEXT);
             mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, null);
 
             RemoteViews contentView = getStandardView(mBuilder.getBigTextLayoutResource());
 
-            mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, oldBuilderContentText);
+            mBuilder.getAllExtras().putCharSequence(EXTRA_TEXT, text);
 
             CharSequence bigTextText = mBuilder.processLegacyText(mBigText);
+            if (TextUtils.isEmpty(bigTextText)) {
+                // In case the bigtext is null / empty fall back to the normal text to avoid a weird
+                // experience
+                bigTextText = mBuilder.processLegacyText(text);
+            }
             contentView.setTextViewText(R.id.big_text, bigTextText);
             contentView.setViewVisibility(R.id.big_text,
                     TextUtils.isEmpty(bigTextText) ? View.GONE : View.VISIBLE);
@@ -4461,8 +4468,8 @@
             mAllowGeneratedReplies = extras.getBoolean(EXTRA_ALLOW_GENERATED_REPLIES,
                     mAllowGeneratedReplies);
             Parcelable[] parcelables = extras.getParcelableArray(EXTRA_MESSAGES);
-            if (parcelables != null && parcelables instanceof Bundle[]) {
-                mMessages = Message.getMessagesFromBundleArray((Bundle[]) parcelables);
+            if (parcelables != null && parcelables instanceof Parcelable[]) {
+                mMessages = Message.getMessagesFromBundleArray(parcelables);
             }
         }
 
@@ -4558,6 +4565,25 @@
             return sb;
         }
 
+        /**
+         * @hide
+         */
+        @Override
+        public RemoteViews makeHeadsUpContentView() {
+            Message m = findLatestIncomingMessage();
+            CharSequence title = mConversationTitle != null
+                    ? mConversationTitle
+                    : (m == null) ? null : m.mSender;
+            CharSequence text = (m == null)
+                    ? null
+                    : mConversationTitle != null ? makeMessageLine(m) : m.mText;
+
+            return mBuilder.applyStandardTemplateWithActions(mBuilder.getBigBaseLayoutResource(),
+                    false /* hasProgress */,
+                    title,
+                    text);
+        }
+
         private static TextAppearanceSpan makeFontColorSpan(int color) {
             return new TextAppearanceSpan(null, 0, 0,
                     ColorStateList.valueOf(color), null);
@@ -4691,12 +4717,14 @@
                 return bundles;
             }
 
-            static List<Message> getMessagesFromBundleArray(Bundle[] bundles) {
+            static List<Message> getMessagesFromBundleArray(Parcelable[] bundles) {
                 List<Message> messages = new ArrayList<>(bundles.length);
                 for (int i = 0; i < bundles.length; i++) {
-                    Message message = getMessageFromBundle(bundles[i]);
-                    if (message != null) {
-                        messages.add(message);
+                    if (bundles[i] instanceof Bundle) {
+                        Message message = getMessageFromBundle((Bundle)bundles[i]);
+                        if (message != null) {
+                            messages.add(message);
+                        }
                     }
                 }
                 return messages;
diff --git a/core/java/android/app/usage/NetworkStats.java b/core/java/android/app/usage/NetworkStats.java
index 6d5c81b..9963eab 100644
--- a/core/java/android/app/usage/NetworkStats.java
+++ b/core/java/android/app/usage/NetworkStats.java
@@ -64,6 +64,11 @@
     private int mUidOrUidIndex;
 
     /**
+     * Tag id in case if was specified in the query.
+     */
+    private int mTag = android.net.NetworkStats.TAG_NONE;
+
+    /**
      * The session while the query requires it, null if all the stats have been collected or close()
      * has been called.
      */
@@ -434,7 +439,7 @@
             mHistory = mSession.getHistoryIntervalForUid(mTemplate, uid,
                     android.net.NetworkStats.SET_ALL, tag,
                     NetworkStatsHistory.FIELD_ALL, mStartTimeStamp, mEndTimeStamp);
-            setSingleUid(uid);
+            setSingleUidTag(uid, tag);
         } catch (RemoteException e) {
             Log.w(TAG, e);
             // Leaving mHistory null
@@ -538,6 +543,7 @@
                 mRecycledHistoryEntry = mHistory.getValues(mEnumerationIndex++,
                         mRecycledHistoryEntry);
                 bucketOut.mUid = Bucket.convertUid(getUid());
+                bucketOut.mTag = Bucket.convertTag(mTag);
                 bucketOut.mState = Bucket.STATE_ALL;
                 bucketOut.mRoaming = Bucket.ROAMING_ALL;
                 bucketOut.mBeginTimeStamp = mRecycledHistoryEntry.bucketStart;
@@ -579,8 +585,9 @@
         return mUidOrUidIndex;
     }
 
-    private void setSingleUid(int uid) {
+    private void setSingleUidTag(int uid, int tag) {
         mUidOrUidIndex = uid;
+        mTag = tag;
     }
 
     private void stepUid() {
diff --git a/core/java/android/content/Loader.java b/core/java/android/content/Loader.java
index e9d82af..c5e0ea7 100644
--- a/core/java/android/content/Loader.java
+++ b/core/java/android/content/Loader.java
@@ -484,7 +484,7 @@
      */
     public void rollbackContentChanged() {
         if (mProcessingChange) {
-            mContentChanged = true;
+            onContentChanged();
         }
     }
 
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 8c73e6a..f9049db 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -3357,7 +3357,7 @@
      * color channel listed in the CFA.</p>
      * <p>This key will be available if {@link CameraCharacteristics#SENSOR_OPTICAL_BLACK_REGIONS android.sensor.opticalBlackRegions} is
      * available or the camera device advertises this key via
-     * {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureRequestKeys }.</p>
+     * {@link android.hardware.camera2.CameraCharacteristics#getAvailableCaptureResultKeys }.</p>
      * <p><b>Range of valid values:</b><br>
      * &gt;= 0 for each.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
diff --git a/core/java/android/net/INetworkPolicyManager.aidl b/core/java/android/net/INetworkPolicyManager.aidl
index a57fac3..2b8b28d 100644
--- a/core/java/android/net/INetworkPolicyManager.aidl
+++ b/core/java/android/net/INetworkPolicyManager.aidl
@@ -52,6 +52,9 @@
     void setRestrictBackground(boolean restrictBackground);
     boolean getRestrictBackground();
 
+    /** Callback used to change internal state on tethering */
+    void onTetheringChanged(String iface, boolean tethering);
+
     /** Control which applications can be exempt from background data restrictions */
     void addRestrictBackgroundWhitelistedUid(int uid);
     void removeRestrictBackgroundWhitelistedUid(int uid);
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index b9a3cff..2c63be2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -1070,6 +1070,9 @@
         public int statSoftIrqTime;
         public int statIdlTime;
 
+        // Platform-level low power state stats
+        public String statPlatformIdleState;
+
         public HistoryStepDetails() {
             clear();
         }
@@ -1099,6 +1102,7 @@
             out.writeInt(statIrqTime);
             out.writeInt(statSoftIrqTime);
             out.writeInt(statIdlTime);
+            out.writeString(statPlatformIdleState);
         }
 
         public void readFromParcel(Parcel in) {
@@ -1119,6 +1123,7 @@
             statIrqTime = in.readInt();
             statSoftIrqTime = in.readInt();
             statIdlTime = in.readInt();
+            statPlatformIdleState = in.readString();
         }
     }
 
@@ -4788,6 +4793,8 @@
                             pw.print(sb);
                             pw.print(")");
                         }
+                        pw.print(", PlatformIdleStat ");
+                        pw.print(rec.stepDetails.statPlatformIdleState);
                         pw.println();
                     } else {
                         pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
@@ -4821,6 +4828,8 @@
                         pw.print(rec.stepDetails.statSoftIrqTime);
                         pw.print(',');
                         pw.print(rec.stepDetails.statIdlTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statPlatformIdleState);
                         pw.println();
                     }
                 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 4ca1b97..2394531 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -726,18 +726,18 @@
             "android.settings.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS";
 
     /**
-     * Activity Action: Show screen for controlling which apps can ignore background data
-     * restrictions.
+     * Activity Action: Show screen for controlling background data
+     * restrictions for a particular application.
      * <p>
-     * Input: if the Intent's data URI is set with an application name (using the "package" schema,
-     * like "package:com.my.app"), then when the screen is displayed it will focus on such app. If
-     * the data is not set, it will just open the screen.
+     * Input: Intent's data URI set with an application name, using the
+     * "package" schema (like "package:com.my.app").
+     *
      * <p>
      * Output: Nothing.
      * <p>
      * Applications can also use {@link android.net.ConnectivityManager#getRestrictBackgroundStatus
-     * ConnectivityManager#getRestrictBackgroundStatus()} to determine the status of the background
-     * data restrictions for them.
+     * ConnectivityManager#getRestrictBackgroundStatus()} to determine the
+     * status of the background data restrictions for them.
      */
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS =
diff --git a/core/java/android/view/WindowManagerInternal.java b/core/java/android/view/WindowManagerInternal.java
index 3ad730b..4b188c4 100644
--- a/core/java/android/view/WindowManagerInternal.java
+++ b/core/java/android/view/WindowManagerInternal.java
@@ -54,13 +54,12 @@
     public interface MagnificationCallbacks {
 
         /**
-         * Called when the bounds of the screen content that is magnified changed.
-         * Note that not the entire screen is magnified.
+         * Called when the region where magnification operates changes. Note that this isn't the
+         * entire screen. For example, IMEs are not magnified.
          *
-         * @param magnifiedBounds the currently magnified region
-         * @param availableBounds the region available for magnification
+         * @param magnificationRegion the current magnification region
          */
-        public void onMagnifiedBoundsChanged(Region magnifiedBounds, Region availableBounds);
+        public void onMagnificationRegionChanged(Region magnificationRegion);
 
         /**
          * Called when an application requests a rectangle on the screen to allow
@@ -158,13 +157,11 @@
     public abstract void setMagnificationSpec(MagnificationSpec spec);
 
     /**
-     * Obtains the magnified and available regions.
+     * Obtains the magnification regions.
      *
-     * @param outMagnified the currently magnified region
-     * @param outAvailable the region available for magnification
+     * @param magnificationRegion the current magnification region
      */
-    public abstract void getMagnificationRegions(@NonNull Region outMagnified,
-            @NonNull Region outAvailable);
+    public abstract void getMagnificationRegion(@NonNull Region magnificationRegion);
 
     /**
      * Gets the magnification and translation applied to a window given its token.
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index bfc87f2..bb1ffcb 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -1308,7 +1308,7 @@
 
         // Include the padding of the list
         int returnedHeight = mListPadding.top + mListPadding.bottom;
-        final int dividerHeight = ((mDividerHeight > 0) && mDivider != null) ? mDividerHeight : 0;
+        final int dividerHeight = mDividerHeight;
         // The previous height value that was less than maxHeight and contained
         // no partial children
         int prevHeightWithoutPartialChild = 0;
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index e69ed35..5358d78 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -108,7 +108,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 142 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 143 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -150,6 +150,13 @@
         public void batterySendBroadcast(Intent intent);
     }
 
+    public interface PlatformIdleStateCallback {
+        public String getPlatformLowPowerStats();
+    }
+
+    private final PlatformIdleStateCallback mPlatformIdleStateCallback;
+
+
     final class MyHandler extends Handler {
         public MyHandler(Looper looper) {
             super(looper, null, true);
@@ -569,6 +576,7 @@
         mDailyFile = null;
         mHandler = null;
         mExternalSync = null;
+        mPlatformIdleStateCallback = null;
         clearHistoryLocked();
     }
 
@@ -2220,6 +2228,12 @@
                     + cur.eventTag.string);
         }
         if (computeStepDetails) {
+            if (mPlatformIdleStateCallback != null) {
+                mCurHistoryStepDetails.statPlatformIdleState =
+                        mPlatformIdleStateCallback.getPlatformLowPowerStats();
+                if (DEBUG) Slog.i(TAG, "WRITE PlatformIdleState:" +
+                        mCurHistoryStepDetails.statPlatformIdleState);
+            }
             computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails);
             if (includeStepDetails != 0) {
                 mCurHistoryStepDetails.writeToParcel(dest);
@@ -7372,11 +7386,16 @@
     }
 
     public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync) {
-        this(new SystemClocks(), systemDir, handler, externalSync);
+        this(new SystemClocks(), systemDir, handler, externalSync, null);
+    }
+
+    public BatteryStatsImpl(File systemDir, Handler handler, ExternalStatsSync externalSync,
+                            PlatformIdleStateCallback cb) {
+        this(new SystemClocks(), systemDir, handler, externalSync, cb);
     }
 
     public BatteryStatsImpl(Clocks clocks, File systemDir, Handler handler,
-            ExternalStatsSync externalSync) {
+            ExternalStatsSync externalSync, PlatformIdleStateCallback cb) {
         init(clocks);
 
         if (systemDir != null) {
@@ -7462,6 +7481,7 @@
         initDischarge();
         clearHistoryLocked();
         updateDailyDeadlineLocked();
+        mPlatformIdleStateCallback = cb;
     }
 
     public BatteryStatsImpl(Parcel p) {
@@ -7477,6 +7497,7 @@
         mExternalSync = null;
         clearHistoryLocked();
         readFromParcel(p);
+        mPlatformIdleStateCallback = null;
     }
 
     public void setPowerProfile(PowerProfile profile) {
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index d36da9f..fb7a19f9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -2428,41 +2428,49 @@
 
     <!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
     <plurals name="duration_minutes_shortest">
+        <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>m</item>
         <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>m</item>
     </plurals>
 
     <!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
     <plurals name="duration_hours_shortest">
+        <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>h</item>
         <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>h</item>
     </plurals>
 
     <!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
     <plurals name="duration_days_shortest">
+        <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>d</item>
         <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>d</item>
     </plurals>
 
     <!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
     <plurals name="duration_years_shortest">
+        <item quantity="one"><xliff:g example="1" id="count">%d</xliff:g>y</item>
         <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>y</item>
     </plurals>
 
     <!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
     <plurals name="duration_minutes_shortest_future">
+        <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>m</item>
         <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>m</item>
     </plurals>
 
     <!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
     <plurals name="duration_hours_shortest_future">
+        <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>h</item>
         <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>h</item>
     </plurals>
 
     <!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
     <plurals name="duration_days_shortest_future">
+        <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>d</item>
         <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>d</item>
     </plurals>
 
     <!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
     <plurals name="duration_years_shortest_future">
+        <item quantity="one">in <xliff:g example="1" id="count">%d</xliff:g>y</item>
         <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>y</item>
     </plurals>
 
diff --git a/docs/html/images/tools/sdk-iadd.png b/docs/html/images/tools/sdk-iadd.png
new file mode 100644
index 0000000..7e35521
--- /dev/null
+++ b/docs/html/images/tools/sdk-iadd.png
Binary files differ
diff --git a/docs/html/images/tools/studio-sdk-manager-packages.png b/docs/html/images/tools/studio-sdk-manager-packages.png
index 356073e..79ea912 100644
--- a/docs/html/images/tools/studio-sdk-manager-packages.png
+++ b/docs/html/images/tools/studio-sdk-manager-packages.png
Binary files differ
diff --git a/docs/html/jd_extras_en.js b/docs/html/jd_extras_en.js
index 53f0703..ad66f79 100644
--- a/docs/html/jd_extras_en.js
+++ b/docs/html/jd_extras_en.js
@@ -3530,7 +3530,6 @@
       "distribute/googleplay/index.html#opportunities",
       "distribute/analyze/improve-roi.html",
       "distribute/users/expand-to-new-markets.html",
-      "distribute/users/promote-with-ads.html",
       "distribute/analyze/index.html",
       "distribute/users/app-invites.html",
       "distribute/users/ota-installs.html",
diff --git a/docs/html/ndk/guides/graphics/validation-layer.jd b/docs/html/ndk/guides/graphics/validation-layer.jd
index 3a61f18..beac1c0 100644
--- a/docs/html/ndk/guides/graphics/validation-layer.jd
+++ b/docs/html/ndk/guides/graphics/validation-layer.jd
@@ -109,10 +109,37 @@
 </li>
 
 <li>
-Prepare to build by following the preparation instructions for your platform. These instructions
-are in the {@code BUILD.md} file contained in the local instance of the repository you cloned.
+Begin preparation for building by entering the following commands on the command line:
+<ul>
+   <li>For Linux or OS X:
+   <ul>
+      <li>
+      <pre class="no-pretty-print">
+$ cd build-android
+$ ./android-generate</pre>
+      </li>
+   </ul>
+   </li>
+
+   <li>For Windows:
+   <ul>
+      <li>
+<pre class="no-pretty-print">
+&gt; cd build-android
+&gt; android-generate.bat</pre>
+      </li>
+   </ul>
+   </li>
+</ul>
 </li>
 
+<li>
+Continue by following the build instructions for your platform.
+These instructions are in the {@code BUILD.md} file contained in the local instance of the
+repository you cloned.
+</li>
+</ul>
+
 </ol>
 
 <h3 id="ias">Android Studio Integration</h3>
@@ -205,12 +232,10 @@
 <p>
 To build validation layers on Linux or OS X, enter these commands on the command line:
 </p>
-<ol>
+<ul>
 <li>
 Using Gradle:
 <pre class="no-pretty-print">
-$ cd build-android
-$ ./android-generate
 $ cd generated/gradle-build
 $ # configure SDK and NDK path in local.properties
 $ gradlew assembleAllDebug
@@ -219,22 +244,17 @@
 <li>
 Using Android makefiles:
 <pre class="no-pretty-print">
-$ cd build-android
-$ ./android-generate
-$ ndk-build
-</pre>
+$ ndk-build</pre>
 </li>
-</ol>
+</ul>
 
 <p>
 To build validation layers on Windows, enter these commands on the command line:
 </p>
-<ol>
+<ul>
 <li>
 Using Gradle:
 <pre class="no-pretty-print">
-&gt; cd build-android
-&gt; android-generate.bat
 &gt; cd generated\gradle-build
 &gt; REM configure SDK and NDK path in local.properties
 &gt; gradlew.bat assembleAllDebug
@@ -243,12 +263,10 @@
 <li>
 Using Android makefiles:
 <pre class="no-pretty-print">
-&gt; cd build-android
-&gt; android-generate.bat
 &gt; ndk-build.cmd
 </pre>
 </li>
-</ol>
+</ul>
 
 
 
diff --git a/docs/html/preview/download.jd b/docs/html/preview/download.jd
index 629bd78..b673fc1 100644
--- a/docs/html/preview/download.jd
+++ b/docs/html/preview/download.jd
@@ -468,18 +468,12 @@
 <p>You can now launch the Android Emulator with the Android N Preview AVD.</p>
 
 <p>
-For the best experience in the Android Emulator, install
-Android Studio 2.1 Preview, which supports the <a
-href="http://tools.android.com/tech-docs/emulator">Android Emulator 2.0 Beta</a>
-with much faster performance compared to the Emulator in
+For the best experience in the Android Emulator, make sure you're using
+Android Studio 2.1 or higher, which supports <a
+href="http://tools.android.com/tech-docs/emulator">Android Emulator 2.0</a>
+with much faster performance compared to the emulator in
 Android Studio 1.5.</p>
 
-<p class="note"><strong>Note:</strong>
-  If you're currently using Android Studio 2.0 Beta, there's a known issue
-  that prevents you from creating AVDs with the N Preview system images, so
-  you currently need to use the Android Studio 2.1 preview to create AVDs.
-</p>
-
 <p>For more information about creating virtual devices, see <a href=
   "{@docRoot}tools/devices/index.html">Managing Virtual Devices</a>.
 </p>
diff --git a/docs/html/preview/j8-jack.jd b/docs/html/preview/j8-jack.jd
index 44e1af0..1f10efa 100644
--- a/docs/html/preview/j8-jack.jd
+++ b/docs/html/preview/j8-jack.jd
@@ -23,7 +23,7 @@
 </p>
 
 <p>To start using these features, you need to download and set up Android
-Studio 2.1 (preview) and the Android N Preview SDK, which includes the required
+Studio 2.1 and the Android N Preview SDK, which includes the required
 Jack toolchain and updated Android Plugin for Gradle. If you haven't yet
 installed the Android N Preview SDK, see <a href=
 "{@docRoot}preview/setup-sdk.html">Set Up to Develop for Android N</a>.</p>
@@ -58,7 +58,7 @@
   <li>
     <a class="external-link" href=
     "https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html">
-    Lambda expressions</a>
+    Lambda expressions</a> (also available on API level 23 and lower)
   </li>
 
   <li>
@@ -70,10 +70,17 @@
   <li>
     <a class="external-link" href=
     "https://docs.oracle.com/javase/tutorial/java/javaOO/methodreferences.html">
-    Method References</a>
+    Method References</a> (also available on API level 23 and lower)
   </li>
 </ul>
 
+<p class="note">
+  <strong>Note:</strong> To test lambda expressions and method references on
+  earlier versions of Android, go to your {@code build.gradle}
+  file, and set {@code compileSdkVersion} and {@code targetSdkVersion} to 23 or
+  lower. You will still need to <a href="#configuration">enable the Jack
+  toolchain</a> to use these Java 8 features.
+</p>
 
 <p>
   Additionally, the following Java 8 language feature APIs are now available:
@@ -125,15 +132,6 @@
   </li>
 </ul>
 
-<p class="note">
-  <strong>Note:</strong> The Android N bases its implementation of
-  lambda expressions on anonymous classes. This approach allows them to be
-  backwards compatible and executable on earlier versions of Android. To test
-  lambda expressions on earlier versions, remember to go to your {@code
-  build.gradle} file, and set {@code compileSdkVersion} and {@code
-  targetSdkVersion} to 23 or lower.
-</p>
-
 <h2 id="configuration">
   Enabling Java 8 Features and the Jack Toolchain
 </h2>
@@ -166,7 +164,7 @@
 
 <p>
   To enable the Java 8 language features and Jack for your project, enter the
-  following in your module-specific {@code build.gradle} file:
+  following in your module-level {@code build.gradle} file:
 </p>
 
 <pre>
@@ -185,7 +183,7 @@
 }
 </pre>
 
-<h3>
+<h3 id="known-issues">
   Known Issues
 </h3>
 
@@ -209,4 +207,4 @@
 </ul>
 
 <p>If you find other problems while using Jack, <a href=
-"http://tools.android.com/filing-bugs">please report bugs</a>.</p>
\ No newline at end of file
+"http://tools.android.com/filing-bugs">please file a bug</a>.</p>
\ No newline at end of file
diff --git a/docs/html/preview/setup-sdk.jd b/docs/html/preview/setup-sdk.jd
index 9e318cf..60568ac 100644
--- a/docs/html/preview/setup-sdk.jd
+++ b/docs/html/preview/setup-sdk.jd
@@ -32,7 +32,7 @@
 <img src="{@docRoot}preview/images/n-preview-setup.png" width="700" alt="" />
 
 
-<h2 id="get-as13">Get Android Studio 2.1 (preview)</h2>
+<h2 id="get-as13">Get Android Studio 2.1</h2>
 
 <p>The Android N platform adds support for <a
 href="{@docRoot}preview/j8-jack.html">Java 8 language features</a>,
@@ -41,55 +41,14 @@
 use Java 8 language features, you need to use Android Studio 2.1 to
 build your app. Otherwise, you don't need to use the Jack compiler, but you
 still need to update to JDK 8 to compile against the Android N platform,
-as described below.
-</p>
+as described below.</p>
 
-<iframe width="400" height="225" src="//www.youtube.com/embed/SBbWGxXCMqQ?autohide=1&amp;showinfo=0" frameborder="0" allowfullscreen="" style="float: right; margin: 0 0 20px 20px;"></iframe>
+<p>If you already have Android Studio installed, make sure you have Android
+Studio 2.1 or higher by clicking <strong>Help > Check for Update</strong>
+(on Mac, <strong>Android Studio > Check for Updates</strong>).</p>
 
-<p>Android Studio 2.1 is currently available as a preview in the canary
-release channel. If you already
-have Android Studio and don't want to update to the canary channel, you can
-download Android Studio 2.1 as a separate installation and use it
-for development with Android N, leaving your primary Android Studio
-environment unaffected.</p>
-
-<p>To download Android Studio 2.1 as a separate installation, follow these
-steps (or if you want to receive Android Studio 2.1 as an update to your
-existing installation, skip to step 6):</p>
-
-<ol>
-  <li>Edit the name of your
-  existing Android Studio installation and append the version number. This way,
-  when you install the new version, it will not override the existing one.</li>
-  <li>Download the appropriate ZIP file for your operating system from the
-    <a href="http://tools.android.com/download/studio/canary/latest"
-    >canary channel download page</a>.
-  </li>
-  <li>Unzip the package and move the Android Studio 2.1 contents to the
-    appropriate location for applications on your system, then launch it.</li>
-  <li>In the setup wizard, click <strong>Next</strong> a couple times to
-  reach the SDK Components Setup screen. Here,
-  you must set a different path for the <strong>Android SDK Location</strong>.
-  It can be any directory you want, but it must not be the default path, which
-  is the same directory used by your original version of Android Studio (unless
-  you changed that one yourself). The SDK location for Android Studio 2.1
-  must be different because the N Preview SDK packages are not compatible with
-  versions of Android Studio lower than 2.1.</p>
-  </li>
-  <li>Continue with the setup wizard until you reach the Android Studio IDE.</li>
-  <li>Open the Settings dialog
-    (<strong>File &gt; Settings</strong> on Windows/Linux, or
-    <strong>Android Studio &gt; Preferences</strong> on Mac). In the left
-    panel, select <strong>Appearance &amp; Behavior &gt; System Settings &gt;
-    Updates</strong>.
-  </li>
-  <li>On the Updates panel, select the <strong>Automatically
-    check updates for</strong> check box and select
-    <strong>Canary Channel</strong> from the drop-down list.
-  </li>
-</ol>
-
-<p>Keep this settings window open for the next step.</p>
+<p>If you don't have it, <a href="{@docRoot}sdk/">download Android Studio
+2.1 here</a>.</p>
 
 
 <h2 id="get-sdk">Get the N Preview SDK</h2>
@@ -98,17 +57,10 @@
 Android N Preview SDK in Android Studio as follows:</p>
 
 <ol>
-  <li>While still viewing the Updates panel (step 4 from above),
-  select the <strong>Automatically
-    check updates for Android SDK</strong> check box and select
-    <strong>Preview Channel</strong> from the drop-down list.
-  </li>
-  <li>Click <strong>Check Now</strong>.</li>
+  <li>Open the SDK Manager by clicking <strong>Tools > Android >
+  SDK Manager</strong>.</li>
 
-  <li>In the left panel, select <strong>Appearance &amp; Behavior &gt;
-  System Settings &gt; Android SDK</strong>.
-
-  <li>Click the <strong>SDK Platforms</strong> tab, then select the
+  <li>In the <strong>SDK Platforms</strong> tab, select the
   <strong>Android N Preview</strong> check box.</li>
 
   <li>Click the <strong>SDK Tools</strong> tab, then select the
@@ -199,7 +151,7 @@
 <pre>
 android {
   compileSdkVersion <strong>'android-N'</strong>
-  buildToolsVersion <strong>'24.0.0-rc1'</strong>
+  buildToolsVersion <strong>'24.0.0-rc3'</strong>
   ...
 
   defaultConfig {
diff --git a/docs/html/samples/_book.yaml b/docs/html/samples/_book.yaml
deleted file mode 100644
index 3fe0d19..0000000
--- a/docs/html/samples/_book.yaml
+++ /dev/null
@@ -1,6 +0,0 @@
-toc:
-- title: About the Samples
-  path: /samples/index.html
-
-- title: What's New
-  path: /samples/new/index.html
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index ddc6e14..94b7e55 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -34,7 +34,7 @@
 
 <p style="margin-top:24px">
   <a class="landing-button green download-bundle-button"
-    data-modal-toggle="studio_tos">Download Android Studio 2.0<br>
+    data-modal-toggle="studio_tos">Download Android Studio 2.1<br>
   <span class="small"></span></a>
 </p>
 
diff --git a/docs/html/sdk/sdk_vars.cs b/docs/html/sdk/sdk_vars.cs
index 9f220d7..6e58ddd 100644
--- a/docs/html/sdk/sdk_vars.cs
+++ b/docs/html/sdk/sdk_vars.cs
@@ -1,27 +1,28 @@
 <?cs
-set:studio.version='2.0.0.20' ?><?cs
-set:studio.release.date='April 7, 2016' ?><?cs
+set:studio.version='2.1.0.9' ?><?cs
+set:studio.release.date='April 26, 2016' ?><?cs
 
 
-set:studio.linux_bundle_download='android-studio-ide-143.2739321-linux.zip' ?><?cs
-set:studio.linux_bundle_bytes='292106971' ?><?cs
-set:studio.linux_bundle_checksum='b64070ee4ec4868e9dd942b56f76864634cb0c67' ?><?cs
+set:studio.linux_bundle_download='android-studio-ide-143.2790544-linux.zip' ?><?cs
+set:studio.linux_bundle_bytes='298122012' ?><?cs
+set:studio.linux_bundle_checksum='45dad9b76ad0506c354483aaa67ea0e2468d03a5' ?><?cs
 
-set:studio.mac_bundle_download='android-studio-ide-143.2739321-mac.dmg' ?><?cs
-set:studio.mac_bundle_bytes='292574501' ?><?cs
-set:studio.mac_bundle_checksum='0f3d53a08815c00912c13738abc79e82207b20ed' ?><?cs
+set:studio.mac_bundle_download='android-studio-ide-143.2790544-mac.dmg' ?><?cs
+set:studio.mac_bundle_bytes='298589307' ?><?cs
+set:studio.mac_bundle_checksum='d667d93ae2e4e0f3fc1b95743329a46222dbf11d' ?><?cs
 
-set:studio.win_bundle_download='android-studio-ide-143.2739321-windows.zip' ?><?cs
-set:studio.win_bundle_bytes='294612422' ?><?cs
-set:studio.win_bundle_checksum='705c00f52b715d6a845c97979ced6f9b1b3f11c6' ?><?cs
+set:studio.win_bundle_download='android-studio-ide-143.2790544-windows.zip' ?><?cs
+set:studio.win_bundle_bytes='300627540' ?><?cs
+set:studio.win_bundle_checksum='9689ba415e5f09e2dcf5263ea302e7b1d98a8fc6' ?><?cs
 
-set:studio.win_bundle_exe_download='android-studio-bundle-143.2739321-windows.exe' ?><?cs
-set:studio.win_bundle_exe_bytes='1223633080' ?><?cs
-set:studio.win_bundle_exe_checksum='c556debf40de6b5d6f6d65d169a64398e3380183' ?><?cs
+set:studio.win_bundle_exe_download='android-studio-bundle-143.2790544-windows.exe' ?><?cs
+set:studio.win_bundle_exe_bytes='1238568304' ?><?cs
+set:studio.win_bundle_exe_checksum='c6abe7980dbb7d1d9887f7341a2942c9e506f891' ?><?cs
 
-set:studio.win_notools_exe_download='android-studio-ide-143.2739321-windows.exe' ?><?cs
-set:studio.win_notools_exe_bytes='277789224' ?><?cs
-set:studio.win_notools_exe_checksum='3e8c25bd7b7f3aa326f7b2a349c4d67c550d13ac' ?><?cs
+set:studio.win_notools_exe_download='android-studio-ide-143.2790544-windows.exe' ?><?cs
+set:studio.win_notools_exe_bytes='283804056' ?><?cs
+set:studio.win_notools_exe_checksum='a2065ba737ddcfb96f4921fee6a038278f46d2a7' ?><?cs
+
 
 
 set:sdk.linux_download='android-sdk_r24.4.1-linux.tgz' ?><?cs
@@ -40,6 +41,7 @@
 set:sdk.win_installer_checksum='f9b59d72413649d31e633207e31f456443e7ea0b' ?><?cs
 
 
+
 set:ndk.mac64_download='android-ndk-r11c-darwin-x86_64.zip' ?><?cs
 set:ndk.mac64_bytes='772428792' ?><?cs
 set:ndk.mac64_checksum='4ce8e7ed8dfe08c5fe58aedf7f46be2a97564696' ?><?cs
diff --git a/docs/html/tools/building/building-studio.jd b/docs/html/tools/building/building-studio.jd
index 7ba716f..2b18b66 100644
--- a/docs/html/tools/building/building-studio.jd
+++ b/docs/html/tools/building/building-studio.jd
@@ -394,11 +394,10 @@
         <li>Change the app manifest
         </li>
 
-        <li>Change resources reference by the app manifest
+        <li>Change resources referenced by the app manifest
         </li>
 
-        <li>Change an Android widget UI element (requires a <a href="#rerun">
-          Clean and Rerun</a>)
+        <li>Change an Android widget UI element
         </li>
       </ul>
     </td>
@@ -415,8 +414,17 @@
         If your build process automatically updates any part of the app manifest,
         such as automatically iterating <code>versionCode</code> or
         <code>versionName</code>, you will not be able to benefit from the full
-        performance of Instant Run. We recommend that you disable automatic updates
-        to any part in the app manifest in your debug build variants.
+        performance of Instant Run. When using Instant Run, you should disable
+        automatic updates to any part in the app manifest in your debug build
+        variants.
+      </p>
+
+      <p>
+        When updating an Android widget UI element, you need to perform a <a href=
+        "#rerun">Clean and Rerun</a> to see your changes. Alternatively, because
+        performing clean builds may take longer while using Instant Run, you can
+        temporarily <a href="#disable-ir">disable Instant Run</a> while making
+        updates to your widget UI.
       </p>
     </td>
   </tr>
@@ -608,7 +616,49 @@
 <p>
   You should experiment with these settings by incrementing their values and
   observing the effect on your build times. You could experience a negative
-  impact to performance if you allocate too many resources to the DEX'ing process.
+  impact to performance if you allocate too many resources to the dexing process.
+</p>
+
+<h4>
+  Enabling dexing-in-process and incremental Java compilation
+</h4>
+
+<p>
+  <a href="{@docRoot}tools/revisions/gradle-plugin.html#revisions">Android
+  Plugin for Gradle version 2.1.0</a> and higher features additional build
+  process improvements, including incremental Java compilation and
+  dexing-in-process. Incremental Java compilation is enabled by default and
+  reduces compilation time during development by only recompiling portions of
+  the source that have changed or need to be recompiled.
+</p>
+
+<p>
+  Dexing-in-process performs dexing within the build process rather than in a
+  separate, external VM processes. This not only makes incremental builds much
+  faster, but also significantly speeds up full builds. To enable this feature,
+  you need to set the Gradle daemon's maximum heap size to at least 2048 MB. You
+  can do this by including the following in your project's
+  <code>gradle.properties</code> file:
+
+<pre>
+org.gradle.jvmargs = -Xmx2048m
+</pre>
+
+</p>
+
+<p>
+  If you have defined a value for <a class="external-link" href=
+  "http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.DexOptions.html#com.android.build.gradle.internal.dsl.DexOptions:javaMaxHeapSize">
+  <code>javaMaxHeapSize</code></a> in your module-level <code>build.gradle</code>
+  file, you need to set the daemon's max heap size to the value of
+  <code>javaMaxHeapSize</code> + 1024 MB. For example, if you have set
+  <code>javaMaxHeapSize</code> to "2g", you need to add the following to your
+  project's <code>gradle.properties</code> file:
+
+<pre>
+org.gradle.jvmargs = -Xmx3072m
+</pre>
+
 </p>
 
 <h4 id="windows-defender">
diff --git a/docs/html/tools/device.jd b/docs/html/tools/device.jd
index 60dce3d..2f39402 100644
--- a/docs/html/tools/device.jd
+++ b/docs/html/tools/device.jd
@@ -211,6 +211,10 @@
     <td><code>109b</code></td>
   </tr>
   <tr>
+    <td>HP</td>
+    <td><code>03f0</code></td>
+  </tr>
+  <tr>
     <td>HTC</td>
     <td><code>0bb4</code></td>
   </tr>
diff --git a/docs/html/tools/help/sdk-manager.jd b/docs/html/tools/help/sdk-manager.jd
index aaa1930..36eac07 100755
--- a/docs/html/tools/help/sdk-manager.jd
+++ b/docs/html/tools/help/sdk-manager.jd
@@ -1,26 +1,39 @@
 page.title=SDK Manager
 @jd:body
 
+<div id="qv-wrapper">
+<div id="qv">
+  <h2>In this document</h2>
+<ol>
+  <li><a href="#updatecheck">Enabling Automatic Update Checking</a></li>
+  <li><a href="#run">Running the SDK Manager</a></li>
+  <li><a href="#Recommended">Recommended Packages</a></li>
+  <li><a href="#AddingSites">Adding New Sites</a></li>
+</ol>
+
+</div>
+</div>
 
 <p>The Android SDK Manager separates the SDK tools, platforms, and other components into packages
 for easy access and management. You can also customize which sites the SDK Manager checks for new
 or updated SDK packages and add-on tools. For example, you can configure the SDK Manager
-to automatically check for updates and notify you when an installed SDK Tools package is updated.
+to automatically check for updates and notify you when updates are available.
 When you receive such a notification, you can then quickly decide whether to download the changes.  </p>
 
-<p>By default, Android Studio does not check for Android SDK updates. To enable automatic Android
-SDK checking: </p>
+<h2 id="updatecheck">Enabling Automatic Update Checking</h2>
+<p>To enable automatic update checking: </p>
 <ol>
   <li>Choose <strong>File</strong> &gt; <strong>Settings</strong>
     &gt; <strong>Appearance & Behavior</strong> &gt; <strong>System Settings</strong>
     &gt; <strong>Updates</strong>. </li>
-  <li>Check the <strong>Automatically check updates for Android SDK</strong> checkbox and select an
+  <li>Select the <strong>Automatically check updates for</strong> checkbox and select an
     <ahref="{@docRoot}tools/studio/studio-config.html#update-channel">update channel</a>.</li>
 
 
   <li>Click <strong>OK</strong> or <strong>Apply</strong> to enable the update checking. </li>
 </ol>
 
+<h2 id="run">Running the SDK Manager</h2>
 <p>You can launch the SDK Manager in one of the following ways:</p>
 <ul>
   <li>From the Android Studio <strong>File</strong> menu:  <strong>File</strong> &gt;
@@ -32,13 +45,17 @@
     (<img src="{@docRoot}images/tools/sdk-manager-studio.png" style="vertical-align:sub;margin:0;height:17px" alt="" />)
     in the menu bar.  </li>
 </ul>
+<p>The SDK Manager appears.</p>
+<img src="{@docRoot}images/tools/studio-sdk-manager-packages.png" alt="" />
+<p class="img-caption"><strong>Figure 1.</strong> The Android SDK Manager shows the
+SDK platforms and packages that are available and installed along with the SDK update sites.</p>
 
 <p class="note"><strong>Tip:</strong> The standalone SDK Manager is still available from the
-command line, but we recommend it only for use with standalone SDK installations.</p>
+command line, but we recommend it for use with standalone SDK installations only.</p>
 
-<p>By default, the SDK Manager installs the latest packages and tools. Click the checkbox next to
+<p>Click the checkbox next to
 each additional SDK platform and tool that you want to install. Clear the
-checkbox to uninstall a SDK platform or tool. Click <strong>Apply</strong> or <strong>OK</strong>
+checkbox to uninstall an SDK platform or tool. Click <strong>Apply</strong> or <strong>OK</strong>
 to update the packages and tools. </p>
 
 <p class="note"><strong>Tip:</strong> When an update is available for an installed
@@ -49,16 +66,14 @@
 (<img src="{@docRoot}images/tools/studio-sdk-removal-icon.png" style="vertical-align:sub;margin:0;height:17px" alt="" />) appears next to the checkbox to
 indicate pending removals.</p>
 
-<p>Click the <em>SDK Update Sites</em> tab to manage which SDK sites Android Studio checks for
+<p>Click the <strong>SDK Update Sites</strong> tab to manage which SDK sites Android Studio checks for
 tool and add-on updates. </p>
 
-<img src="{@docRoot}images/tools/studio-sdk-manager-packages.png" alt="" />
-<p class="img-caption"><strong>Figure 1.</strong> The Android SDK Manager shows the
-SDK platforms and packages that are available and installed along with the SDK update sites.</p>
 
-<p>There are several different packages available for the Android SDK. The table below describes
+
+<p>There are several different packages available for the Android SDK. The following section describes
 most of the available packages and where they're located in your SDK directory
-once you download them.</p>
+after you download them.</p>
 
 
 
@@ -76,43 +91,44 @@
     Be sure to respond to the Android Studio update prompts to keep your SDK Platform-tools
     up-to-date.</dd>
   <dt>SDK Platform</dt>
-  <dd><strong>Required.</strong><em> At least one platform</em> is required in your
-environment so you're able to compile your application. In order to provide the best user experience
+  <dd><strong>Required.</strong> At least one platform is required in your
+environment to be able to compile your application. To provide the best user experience
 on the latest devices, we recommend that you use the latest platform version as your build target.
 You'll still be able to run your app on older versions, but you must build against the latest
 version in order to use new features when running on devices with the latest version of Android.
-  <p>The SDK Manager downloads the latest Android version. It also downloads the earliest version
-  of Android (Android 2.2 (API level 8)) that we recommend that your app support. </p></dd>
+  </dd>
   <dt>System Image</dt>
   <dd>Recommended. Although you might have one or more Android-powered devices on which to test
  your app, it's unlikely you have a device for every version of Android your app supports. It's
-a good practice to download system images for all versions of Android your app supports and test
-your app running on them with the
-<a href="{@docRoot}tools/devices/emulator.html">Android emulator</a>. Each SDK platform package
-contains the supported system images. Click <strong>Show Package Details</strong> to display the available
+a good practice to download system images for all versions of Android that your
+app supports and then test
+your app against these Android versions by using the
+<a href="{@docRoot}tools/devices/emulator.html">Android Emulator</a>. Click <strong>Show Package Details</strong> to display the available
 system images for each available platform. You can also download system images when creating
 Android Virtual Devices (AVDs) in the
 <a href="{@docRoot}tools/help/avd-manager.html">AVD Manager</a>. </dd>
 
-  <dt>Android Support Library</dt>
-  <dd>Recommended. Includes a static library that provides an extended set of
-  APIs that are compatible with most versions of Android. It's required for
+
+  <dt>Android Support Repository</dt>
+  <dd>Recommended. Includes a local Maven repository for the Android Data
+  Binding Library, Android Testing Support Library, and Android Support
+  Libraries. The Android Support Libraries provide an extended set of
+  APIs that are compatible with most versions of Android. They're required for
   products such as <a href="{@docRoot}wear/index.html">Android Wear</a>, <a
   href="{@docRoot}tv/index.html">Android TV</a>, and <a
   href="https://developers.google.com/cast/">Google Cast</a>. For more
-  information, read <a href="{@docRoot}tools/support-library/index.html">Support
-  Library</a>.
-  </dd>
-
-  <dt>Android Support Repository</dt>
-  <dd>Recommended. Includes local Maven repository for Support libraries.</dd>
+  information about each of the libraries in the Android Support Repository,
+  see <a href="{@docRoot}tools/data-binding/guide.html">Data Binding Guide</a>,
+  <a href="{@docRoot}tools/testing-support-library/index.html">Testing Support
+  Library</a>, and <a href="{@docRoot}tools/support-library/index.html">Support
+  Library</a>.</dd>
 
   <dt>Google Play services</dt>
   <dd>Recommended. Includes the Google Play services client library, which
-  provides a variety of features and services for your 
+  provides a variety of features and services for your
   apps, such as <a
   href="https://developers.google.com/identity/sign-in/android/">Google
-  sign-in</a>,<a
+  sign-in</a>, <a
   href="https://developers.google.com/maps/documentation/android-api/">Google
   Maps</a>, <a href="https://developers.google.com/games/services/">Games
   achievements and leaderboards</a>, and much more.</dd>
@@ -122,45 +138,44 @@
 
 
 <p class="note"><strong>Tip:</strong> For easy access to the SDK tools from a command line, add the
-location of the SDK's <code>tools/</code> and
+location of the SDK <code>tools/</code> and
 <code>platform-tools</code> to your <code>PATH</code> environment variable.</p>
 
 
-<p>The above list is not comprehensive and you can <a
+<p>The previous list is not comprehensive and you can <a
 href="#AddingSites">add new sites</a> to download additional packages from third parties.</p>
 
 <p>In some cases, an SDK package may require a specific minimum revision of
-another package or SDK tool.
-The development tools will notify you with warnings if there is dependency that you need to
-address. The Android SDK Manager also enforces dependencies by requiring any
-packages that are needed by those you have selected.</p>
+another package or SDK tool. The SDK Manager automatically notifies you of any
+dependencies and downloads the required packages or tools.
+In addition, development tools notify you if there are dependencies that you need to
+address. </p>
 
 
 
 <h2 id="AddingSites">Adding New Sites</h2>
 
-<p>The <em>SDK Update Sites</em> tab displays the sites that Android Studio checks for Android SDK
-and third-party updates. You can add other sites that host their own Android SDK add-ons, then
+<p>The <strong>SDK Update Sites</strong> tab displays the sites that Android Studio checks for Android SDK
+and third-party updates. You can add other sites that host their own Android SDK add-ons, and then
 download the SDK add-ons from those sites.</p>
 
 <p>For example, a mobile carrier or device manufacturer might offer additional
-API libraries that are supported by their own Android-powered devices. In order
-to develop using their libraries, you must install their Android SDK add-on, if it's not already
-available as a <em>third-party add-on</em>. </p>
+API libraries that are supported by their own Android-powered devices.
+To develop using their libraries, you must install their Android SDK add-on, if it's not already
+available as a third-party add-on.</p>
 
 <p>If a carrier or device manufacturer has hosted an SDK add-on repository file
 on their website, follow these steps to add their site to the Android SDK Manager:</p>
 
 <ol>
   <li>Click the <strong>SDK Update Sites</strong> tab.</li>
-  <li>Click the <strong>Add</strong> icon in the tools area and enter the name and URL of the
-    <code>add-on</code> site.</li>
-  <li>Click <strong>OK</strong>.</li>
-  <li>Make sure the checkbox is checked in the <em>Enabled</em> column.</li>
-  <li>Click <strong>OK</strong> or <strong>Apply</strong>.</li>
-</ol>
-<p>Any SDK packages available from the site appear in the <em>SDK Platforms</em> or
-<em>SDK Tools</em> tabs.</p>
+  <li>Click <strong>Add</strong> <img src="{@docRoot}images/tools/sdk-iadd.png" style="vertical-align:sub;margin:0;height:17px" alt="" />. </li>
+  <li>Type the name and URL of the
+    add-on site, and then cick <strong>OK</strong>.</li>
+  <li>Make sure the checkbox is selected in the <strong>Enabled</strong> column.</li>
 
+<p>Any SDK packages available from the site appear in the <strong>SDK Platforms</strong> or
+<strong>SDK Tools</strong> tabs.</p>
+</ol>
 
 
diff --git a/docs/html/tools/revisions/gradle-plugin.jd b/docs/html/tools/revisions/gradle-plugin.jd
index 20492f7..f77cfd6 100644
--- a/docs/html/tools/revisions/gradle-plugin.jd
+++ b/docs/html/tools/revisions/gradle-plugin.jd
@@ -73,7 +73,7 @@
   Structure</strong> &gt; <strong>Project</strong> menu in Android Studio, or
   the top-level <code>build.gradle</code> file. The plugin version applies to
   all modules built in that Android Studio project. The following example sets
-  the Android Plugin for Gradle to version 2.0.0 from the
+  the Android Plugin for Gradle to version 2.1.0 from the
   <code>build.gradle</code> file:
 </p>
 
@@ -81,7 +81,7 @@
 buildscript {
   ...
   dependencies {
-    classpath 'com.android.tools.build:gradle:2.0.0'
+    classpath 'com.android.tools.build:gradle:2.1.0'
   }
 }
 </pre>
@@ -138,6 +138,108 @@
 <div class="toggle-content opened">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/styles/disclosure_up.png" class="toggle-content-img"
+      alt=""/>Android Plugin for Gradle, Revision 2.1.0</a> <em>(April 2016)</em>
+  </p>
+
+  <div class="toggle-content-toggleme">
+    <dl>
+    <dt>Dependencies:</dt>
+
+    <dd>
+      <ul>
+        <li>Gradle 2.10 or higher.
+        </li>
+
+        <li>
+          <a href="{@docRoot}tools/revisions/build-tools.html">Build Tools 23.0.2</a>
+          or higher.
+        </li>
+      </ul>
+    </dd>
+
+    <dt>New:</dt>
+    <dd>
+      <ul>
+        <li>Added support for the N Developer Preview, JDK 8, and <a href=
+        "{@docRoot}preview/j8-jack.html">Java 8 language features</a> using the Jack
+        toolchain. To find out more, read the <a href=
+        "{@docRoot}preview/overview.html">N Preview guide</a>.
+
+          <p class="note">
+            <strong>Note:</strong> <a href=
+            "{@docRoot}tools/building/building-studio.html#instant-run">Instant
+            Run</a> does not currently work with Jack and will be disabled while
+            using the new toolchain. You only need to use Jack if you are developing
+            for the N Preview and want to use the supported Java 8 language features.
+          </p>
+        </li>
+
+        <li>Added default support for incremental Java compilation to reduce
+        compilation time during development. It does this by only recompiling
+        portions of the source that have changed or need to be recompiled. To disable
+        this feature, add the following code to your module-level
+        <code>build.gradle</code> file:
+
+<pre>
+android {
+  ...
+  compileOptions {
+    incremental false
+  }
+}
+</pre>
+        </li>
+
+        <li>
+          <p>
+          Added support for dexing-in-process which performs dexing within the build
+          process rather than in a separate, external VM processes. This not only makes
+          incremental builds faster, but also speeds up full builds. The feature is
+          enabled by default for projects that have set the Gradle daemon's maximum heap
+          size to at least 2048 MB. You can do this by including the following in your
+          project's <code>gradle.properties</code> file:
+
+<pre>
+org.gradle.jvmargs = -Xmx2048m
+</pre>
+          </p>
+
+          <p>
+          If you have defined a value for <a class="external-link" href=
+          "http://google.github.io/android-gradle-dsl/current/com.android.build.gradle.internal.dsl.DexOptions.html#com.android.build.gradle.internal.dsl.DexOptions:javaMaxHeapSize">
+          <code>javaMaxHeapSize</code></a> in your module-level <code>build.gradle</code>
+          file, you need to set <code>org.gradle.jvmargs</code> to the value of
+          <code>javaMaxHeapSize</code> + 1024 MB. For example, if you have set
+          <code>javaMaxHeapSize</code> to "2048m", you need to add the following to your
+          project's <code>gradle.properties</code> file:
+
+<pre>
+org.gradle.jvmargs = -Xmx3072m
+</pre>
+          </p>
+
+          <p>
+            To disable dexing-in-process, add the following code to your module-level
+            <code>build.gradle</code> file:
+
+<pre>
+android {
+  ...
+  dexOptions {
+      dexInProcess false
+  }
+}
+</pre>
+          </p>
+        </li>
+      </ul>
+    </dd>
+  </div>
+</div>
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/styles/disclosure_down.png" class="toggle-content-img"
       alt=""/>Android Plugin for Gradle, Revision 2.0.0</a> <em>(April 2016)</em>
   </p>
 
diff --git a/docs/html/tools/revisions/studio.jd b/docs/html/tools/revisions/studio.jd
index 9579ae2..5747f52 100755
--- a/docs/html/tools/revisions/studio.jd
+++ b/docs/html/tools/revisions/studio.jd
@@ -49,9 +49,52 @@
 <p>The sections below provide notes about successive releases of
 Android Studio, as denoted by revision number. </p>
 
+
 <div class="toggle-content open">
   <p><a href="#" onclick="return toggleContent(this)">
     <img src="{@docRoot}assets/images/styles/disclosure_up.png" class="toggle-content-img"
+      alt=""/>Android Studio v2.1.0</a> <em>(April 2016)</em>
+  </p>
+  <div class="toggle-content-toggleme">
+
+<p>The primary changes in this update provide support for development with the
+<a href="{@docRoot}preview/index.html">Android N Preview</a>.</p>
+
+<p>The Android N platform adds support for <a
+href="{@docRoot}preview/j8-jack.html">Java 8 language features</a>, which
+require a new experimental compiler called Jack. The latest version of Jack is
+currently supported only in Android Studio 2.1. So if you want to use Java 8
+language features, you need to use Android Studio 2.1 to build your app.</p>
+
+<p class="note"><strong>Note:</strong> <a
+href="{@docRoot}tools/building/building-studio.html#instant-run">Instant Run</a>
+is disabled when you enable the Jack compiler because they currently are not
+compatible.</p>
+
+<p>Although Android Studio 2.1 is now stable, the Jack compiler is still
+experimental and you must enable it with <a
+href="{@docRoot}preview/j8-jack.html#configuration">the <code>jackOptions</code>
+property</a> in your <code>build.gradle</code> file.</p>
+
+<p>Other than the changes to support the N Preview, Android Studio 2.1
+includes minor bug fixes and the following enhancements:</p>
+    <ul>
+      <li>The Java-aware C++ debugger is now enabled by default when you're
+using an N device or emulator and select <strong>Native</strong> debugger mode
+(in the <strong>Debugger</strong> tab for your run/debug configuration).</li>
+    </ul>
+    <p>For other build enhancements, including incremental Java compilation
+    and dexing-in-process, update your <a
+href="{@docRoot}tools/revisions/gradle-plugin.html">Android Plugin for
+Gradle</a> to version 2.1.0.</p>
+  </div>
+</div>
+
+
+
+<div class="toggle-content closed">
+  <p><a href="#" onclick="return toggleContent(this)">
+    <img src="{@docRoot}assets/images/styles/disclosure_down.png" class="toggle-content-img"
       alt=""/>Android Studio v2.0.0</a> <em>(April 2016)</em>
   </p>
 
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 8251ee6..0f670a8 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -569,7 +569,7 @@
                 op.unmappedBounds.getWidth(), op.unmappedBounds.getHeight(), op.paint);
         const AutoTexture holder(texture);
         if (CC_LIKELY(holder.texture)) {
-            renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.right,
+            renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
                     *texture, *(op.paint));
         }
     } else {
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index 781f88c..de57cd1e 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -21,6 +21,8 @@
 #include <BakedOpRenderer.h>
 #include <tests/common/TestUtils.h>
 
+#include <SkDashPathEffect.h>
+
 using namespace android::uirenderer;
 
 static BakedOpRenderer::LightInfo sLightInfo;
@@ -71,12 +73,17 @@
     ASSERT_EQ(1, glopCount) << "Exactly one Glop expected";
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, onArc_position) {
+RENDERTHREAD_TEST(BakedOpDispatcher, pathTexture_positionOvalArc) {
     SkPaint strokePaint;
     strokePaint.setStyle(SkPaint::kStroke_Style);
     strokePaint.setStrokeWidth(4);
-    ArcOp op(Rect(10, 15, 20, 25), Matrix4::identity(), nullptr, &strokePaint, 0, 270, true);
-    testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) {
+
+    float intervals[] = {1.0f, 1.0f};
+    auto dashEffect = SkDashPathEffect::Create(intervals, 2, 0);
+    strokePaint.setPathEffect(dashEffect);
+    dashEffect->unref();
+
+    auto textureGlopVerifier = [] (const Glop& glop) {
         // validate glop produced by renderPathTexture (so texture, unit quad)
         auto texture = glop.fill.texture.texture;
         ASSERT_NE(nullptr, texture);
@@ -85,15 +92,20 @@
                 << "Should see conservative offset from PathCache::computeBounds";
         Rect expectedBounds(10, 15, 20, 25);
         expectedBounds.outset(expectedOffset);
-#if !HWUI_NEW_OPS
-        EXPECT_EQ(expectedBounds, glop.bounds) << "bounds outset by stroke 'offset'";
-#endif
+
         Matrix4 expectedModelView;
         expectedModelView.loadTranslate(10 - expectedOffset, 15 - expectedOffset, 0);
         expectedModelView.scale(10 + 2 * expectedOffset, 10 + 2 * expectedOffset, 1);
         EXPECT_EQ(expectedModelView, glop.transform.modelView)
                 << "X and Y offsets, and scale both applied to model view";
-    });
+    };
+
+    // Arc and Oval will render functionally the same glop, differing only in texture content
+    ArcOp arcOp(Rect(10, 15, 20, 25), Matrix4::identity(), nullptr, &strokePaint, 0, 270, true);
+    testUnmergedGlopDispatch(renderThread, &arcOp, textureGlopVerifier);
+
+    OvalOp ovalOp(Rect(10, 15, 20, 25), Matrix4::identity(), nullptr, &strokePaint);
+    testUnmergedGlopDispatch(renderThread, &ovalOp, textureGlopVerifier);
 }
 
 RENDERTHREAD_TEST(BakedOpDispatcher, onLayerOp_bufferless) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index db720bb..5ff9c0c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -846,7 +846,7 @@
 
                 // Special case for location (sigh).
                 if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
-                    return null;
+                    continue;
                 }
 
                 Setting setting = mSettingsRegistry.getSettingLocked(
@@ -871,7 +871,8 @@
 
         // Special case for location (sigh).
         if (isLocationProvidersAllowedRestricted(name, callingUserId, owningUserId)) {
-            return null;
+            return mSettingsRegistry.getSettingsLocked(SETTINGS_TYPE_SECURE,
+                    owningUserId).getNullSetting();
         }
 
         // Get the value.
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 6dfd0e6..2de0618c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -16,7 +16,6 @@
 
 package com.android.providers.settings;
 
-import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
@@ -159,6 +158,10 @@
         return mVersion;
     }
 
+    public Setting getNullSetting() {
+        return mNullSetting;
+    }
+
     // The settings provider must hold its lock when calling here.
     public void setVersionLocked(int version) {
         if (version == mVersion) {
diff --git a/packages/SystemUI/src/com/android/systemui/Prefs.java b/packages/SystemUI/src/com/android/systemui/Prefs.java
index 28ed84f..907616c 100644
--- a/packages/SystemUI/src/com/android/systemui/Prefs.java
+++ b/packages/SystemUI/src/com/android/systemui/Prefs.java
@@ -44,6 +44,7 @@
         Key.TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN,
         Key.QS_HOTSPOT_ADDED,
         Key.QS_DATA_SAVER_ADDED,
+        Key.QS_DATA_SAVER_DIALOG_SHOWN,
         Key.QS_INVERT_COLORS_ADDED,
         Key.QS_WORK_ADDED,
         Key.QS_NIGHT_ADDED,
@@ -63,6 +64,7 @@
         String TV_PICTURE_IN_PICTURE_ONBOARDING_SHOWN = "TvPictureInPictureOnboardingShown";
         String QS_HOTSPOT_ADDED = "QsHotspotAdded";
         String QS_DATA_SAVER_ADDED = "QsDataSaverAdded";
+        String QS_DATA_SAVER_DIALOG_SHOWN = "QsDataSaverDialogShown";
         String QS_INVERT_COLORS_ADDED = "QsInvertColorsAdded";
         String QS_WORK_ADDED = "QsWorkAdded";
         String QS_NIGHT_ADDED = "QsNightAdded";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
index dded595..0ce805e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DataSaverTile.java
@@ -14,12 +14,15 @@
 
 package com.android.systemui.qs.tiles;
 
+import android.content.DialogInterface;
 import android.content.Intent;
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.statusbar.policy.DataSaverController;
 
 public class DataSaverTile extends QSTile<QSTile.BooleanState> implements
@@ -53,6 +56,29 @@
 
     @Override
     protected void handleClick() {
+        if (Prefs.getBoolean(mContext, Prefs.Key.QS_DATA_SAVER_DIALOG_SHOWN, false)) {
+            // Do it right away.
+            toggleDataSaver();
+            return;
+        }
+        // Shows dialog first
+        SystemUIDialog dialog = new SystemUIDialog(mContext);
+        dialog.setTitle(com.android.internal.R.string.data_saver_enable_title);
+        dialog.setMessage(com.android.internal.R.string.data_saver_description);
+        dialog.setPositiveButton(com.android.internal.R.string.data_saver_enable_button,
+                new DialogInterface.OnClickListener() {
+                    @Override
+                    public void onClick(DialogInterface dialog, int which) {
+                        toggleDataSaver();
+                    }
+                });
+        dialog.setNegativeButton(com.android.internal.R.string.cancel, null);
+        dialog.setShowForAllUsers(true);
+        dialog.show();
+        Prefs.putBoolean(mContext, Prefs.Key.QS_DATA_SAVER_DIALOG_SHOWN, true);
+    }
+
+    private void toggleDataSaver() {
         mState.value = !mDataSaverController.isDataSaverEnabled();
         MetricsLogger.action(mContext, getMetricsCategory(), mState.value);
         mDataSaverController.setDataSaverEnabled(mState.value);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 8239425..5b16fce 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -277,6 +277,10 @@
         int intrinsicBefore = getIntrinsicHeight();
         mIsHeadsUp = isHeadsUp;
         mPrivateLayout.setHeadsUp(isHeadsUp);
+        if (mIsSummaryWithChildren) {
+            // The overflow might change since we allow more lines as HUN.
+            mChildrenContainer.updateGroupOverflow();
+        }
         if (intrinsicBefore != getIntrinsicHeight()) {
             notifyHeightChanged(false  /* needsAnimation */);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 7be50c4..81303fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar;
 
 import android.app.Notification;
+import android.app.PendingIntent;
 import android.app.RemoteInput;
 import android.content.Context;
 import android.graphics.Rect;
@@ -118,6 +119,8 @@
     private int mTransformationStartVisibleType;
     private boolean mUserExpanding;
     private int mSingleLineWidthIndention;
+    private PendingIntent mPreviousExpandedRemoteInputIntent;
+    private PendingIntent mPreviousHeadsUpRemoteInputIntent;
 
     public NotificationContentView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -280,13 +283,19 @@
             mContractedChild.animate().cancel();
             removeView(mContractedChild);
         }
+        mPreviousExpandedRemoteInputIntent =
+                mExpandedRemoteInput != null ? mExpandedRemoteInput.getPendingIntent() : null;
         if (mExpandedChild != null) {
             mExpandedChild.animate().cancel();
             removeView(mExpandedChild);
+            mExpandedRemoteInput = null;
         }
+        mPreviousHeadsUpRemoteInputIntent =
+                mHeadsUpRemoteInput != null ? mHeadsUpRemoteInput.getPendingIntent() : null;
         if (mHeadsUpChild != null) {
             mHeadsUpChild.animate().cancel();
             removeView(mHeadsUpChild);
+            mHeadsUpRemoteInput = null;
         }
         mContractedChild = null;
         mExpandedChild = null;
@@ -496,6 +505,12 @@
         }
         int visibleType = calculateVisibleType();
         if (visibleType != mVisibleType || force) {
+            View visibleView = getViewForVisibleType(visibleType);
+            if (visibleView != null) {
+                visibleView.setVisibility(VISIBLE);
+                transferRemoteInputFocus(visibleType);
+            }
+
             if (animate && ((visibleType == VISIBLE_TYPE_EXPANDED && mExpandedChild != null)
                     || (visibleType == VISIBLE_TYPE_HEADSUP && mHeadsUpChild != null)
                     || (visibleType == VISIBLE_TYPE_SINGLELINE && mSingleLineView != null)
@@ -559,6 +574,19 @@
         });
     }
 
+    private void transferRemoteInputFocus(int visibleType) {
+        if (visibleType == VISIBLE_TYPE_HEADSUP
+                && mHeadsUpRemoteInput != null
+                && (mExpandedRemoteInput != null && mExpandedRemoteInput.isActive())) {
+            mHeadsUpRemoteInput.stealFocusFrom(mExpandedRemoteInput);
+        }
+        if (visibleType == VISIBLE_TYPE_EXPANDED
+                && mExpandedRemoteInput != null
+                && (mHeadsUpRemoteInput != null && mHeadsUpRemoteInput.isActive())) {
+            mExpandedRemoteInput.stealFocusFrom(mHeadsUpRemoteInput);
+        }
+    }
+
     /**
      * @param visibleType one of the static enum types in this view
      * @return the corresponding transformable view according to the given visible type
@@ -736,6 +764,8 @@
         updateShowingLegacyBackground();
         selectLayout(false /* animate */, true /* force */);
         setDark(mDark, false /* animate */, 0 /* delay */);
+        mPreviousExpandedRemoteInputIntent = null;
+        mPreviousHeadsUpRemoteInputIntent = null;
     }
 
     private void updateSingleLineView() {
@@ -771,19 +801,23 @@
 
         View bigContentView = mExpandedChild;
         if (bigContentView != null) {
-            mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput);
+            mExpandedRemoteInput = applyRemoteInput(bigContentView, entry, hasRemoteInput,
+                    mPreviousExpandedRemoteInputIntent);
         } else {
             mExpandedRemoteInput = null;
         }
+
         View headsUpContentView = mHeadsUpChild;
         if (headsUpContentView != null) {
-            mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput);
+            mHeadsUpRemoteInput = applyRemoteInput(headsUpContentView, entry, hasRemoteInput,
+                    mPreviousHeadsUpRemoteInputIntent);
         } else {
             mHeadsUpRemoteInput = null;
         }
     }
 
-    private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry, boolean hasRemoteInput) {
+    private RemoteInputView applyRemoteInput(View view, NotificationData.Entry entry,
+            boolean hasRemoteInput, PendingIntent existingPendingIntent) {
         View actionContainerCandidate = view.findViewById(
                 com.android.internal.R.id.actions_container);
         if (actionContainerCandidate instanceof FrameLayout) {
@@ -814,6 +848,24 @@
                 existing.setBackgroundColor(NotificationColorUtil.ensureTextBackgroundColor(color,
                         mContext.getColor(R.color.remote_input_text),
                         mContext.getColor(R.color.remote_input_hint)));
+
+                if (existingPendingIntent != null || existing.isActive()) {
+                    // The current action could be gone, or the pending intent no longer valid.
+                    // If we find a matching action in the new notification, focus, otherwise close.
+                    Notification.Action[] actions = entry.notification.getNotification().actions;
+                    if (existingPendingIntent != null) {
+                        existing.setPendingIntent(existingPendingIntent);
+                    }
+                    if (existing.updatePendingIntentFromActions(actions)) {
+                        if (!existing.isActive()) {
+                            existing.focus();
+                        }
+                    } else {
+                        if (existing.isActive()) {
+                            existing.close();
+                        }
+                    }
+                }
             }
             return existing;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index 3c95a78..4ce330c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -52,7 +52,7 @@
         // This also clears the existing types
         super.updateTransformedTypes();
         if (mActions != null) {
-            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_TEXT,
+            mTransformationHelper.addTransformedView(TransformableView.TRANSFORMING_VIEW_ACTIONS,
                     mActions);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
index 7a6d080..ddded49 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -25,12 +25,14 @@
 import com.android.systemui.R;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.phone.StatusBarWindowView;
+import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 
 /**
  * Controls showing and hiding of the brightness mirror.
  */
 public class BrightnessMirrorController {
 
+    private final NotificationStackScrollLayout mStackScroller;
     public long TRANSITION_DURATION_OUT = 150;
     public long TRANSITION_DURATION_IN = 200;
 
@@ -45,10 +47,13 @@
         mScrimBehind = (ScrimView) statusBarWindow.findViewById(R.id.scrim_behind);
         mBrightnessMirror = statusBarWindow.findViewById(R.id.brightness_mirror);
         mNotificationPanel = statusBarWindow.findViewById(R.id.notification_panel);
+        mStackScroller = (NotificationStackScrollLayout) statusBarWindow.findViewById(
+                R.id.notification_stack_scroller);
     }
 
     public void showMirror() {
         mBrightnessMirror.setVisibility(View.VISIBLE);
+        mStackScroller.setFadedOut(true);
         mScrimBehind.animateViewAlpha(0.0f, TRANSITION_DURATION_OUT, Interpolators.ALPHA_OUT);
         outAnimation(mNotificationPanel.animate())
                 .withLayer();
@@ -62,6 +67,7 @@
                     @Override
                     public void run() {
                         mBrightnessMirror.setVisibility(View.INVISIBLE);
+                        mStackScroller.setFadedOut(false);
                     }
                 });
     }
@@ -69,7 +75,8 @@
     private ViewPropertyAnimator outAnimation(ViewPropertyAnimator a) {
         return a.alpha(0.0f)
                 .setDuration(TRANSITION_DURATION_OUT)
-                .setInterpolator(Interpolators.ALPHA_OUT);
+                .setInterpolator(Interpolators.ALPHA_OUT)
+                .withEndAction(null);
     }
     private ViewPropertyAnimator inAnimation(ViewPropertyAnimator a) {
         return a.alpha(1.0f)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index ecd1772..0fdd99f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.policy;
 
+import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.RemoteInput;
 import android.content.Context;
@@ -197,6 +198,7 @@
     }
 
     public void focus() {
+        setVisibility(VISIBLE);
         mController.addRemoteInput(mEntry);
         mEditText.setInnerFocusable(true);
         mEditText.mShowImeOnInputConnection = true;
@@ -275,6 +277,63 @@
         }
     }
 
+    public boolean isActive() {
+        return mEditText.isFocused();
+    }
+
+    public void stealFocusFrom(RemoteInputView other) {
+        other.close();
+        setPendingIntent(other.mPendingIntent);
+        setRemoteInput(other.mRemoteInputs, other.mRemoteInput);
+        focus();
+    }
+
+    /**
+     * Tries to find an action in {@param actions} that matches the current pending intent
+     * of this view and updates its state to that of the found action
+     *
+     * @return true if a matching action was found, false otherwise
+     */
+    public boolean updatePendingIntentFromActions(Notification.Action[] actions) {
+        boolean found = false;
+        if (mPendingIntent == null || actions == null) {
+            return false;
+        }
+        Intent current = mPendingIntent.getIntent();
+        if (current == null) {
+            return false;
+        }
+
+        for (Notification.Action a : actions) {
+            RemoteInput[] inputs = a.getRemoteInputs();
+            if (a.actionIntent == null || inputs == null) {
+                continue;
+            }
+            Intent candidate = a.actionIntent.getIntent();
+            if (!current.filterEquals(candidate)) {
+                continue;
+            }
+
+            RemoteInput input = null;
+            for (RemoteInput i : inputs) {
+                if (i.getAllowFreeFormInput()) {
+                    input = i;
+                }
+            }
+            if (input == null) {
+                continue;
+            }
+            setPendingIntent(a.actionIntent);
+            setRemoteInput(inputs, input);
+            return true;
+        }
+        return false;
+    }
+
+    public PendingIntent getPendingIntent() {
+        return mPendingIntent;
+    }
+
     /**
      * An EditText that changes appearance based on whether it's focusable and becomes
      * un-focusable whenever the user navigates away from it or it becomes invisible.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
index be98d7a..a1e89b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
@@ -139,7 +139,9 @@
         for (int i = 0; i < childCount; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
             boolean isOverflow = i == overflowIndex;
-            child.setSingleLineWidthIndention(isOverflow ? mOverflowNumber.getMeasuredWidth() : 0);
+            child.setSingleLineWidthIndention(isOverflow && mOverflowNumber != null
+                    ? mOverflowNumber.getMeasuredWidth()
+                    : 0);
             child.measure(widthMeasureSpec, newHeightSpec);
             height += child.getMeasuredHeight();
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 3e0f930..9603e81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -23,6 +23,7 @@
 import android.animation.TimeAnimator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.annotation.FloatRange;
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -327,6 +328,8 @@
     };
     private PorterDuffXfermode mSrcMode = new PorterDuffXfermode(PorterDuff.Mode.SRC);
     private boolean mPulsing;
+    private boolean mDrawBackgroundAsSrc;
+    private boolean mFadedOut;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -439,7 +442,12 @@
     }
 
     public void setDrawBackgroundAsSrc(boolean asSrc) {
-        mBackgroundPaint.setXfermode(asSrc ? mSrcMode : null);
+        mDrawBackgroundAsSrc = asSrc;
+        updateSrcDrawing();
+    }
+
+    private void updateSrcDrawing() {
+        mBackgroundPaint.setXfermode(mDrawBackgroundAsSrc && !mFadedOut ? mSrcMode : null);
         invalidate();
     }
 
@@ -1743,7 +1751,9 @@
     }
 
     private void applyCurrentBackgroundBounds() {
-        mScrimController.setExcludedBackgroundArea(mCurrentBounds);
+        if (!mFadedOut) {
+            mScrimController.setExcludedBackgroundArea(mCurrentBounds);
+        }
         invalidate();
     }
 
@@ -3421,6 +3431,24 @@
         updateNotificationAnimationStates();
     }
 
+    public void setFadedOut(boolean fadingOut) {
+        if (fadingOut != mFadedOut) {
+            mFadedOut = fadingOut;
+            if (fadingOut) {
+                mScrimController.setExcludedBackgroundArea(null);
+            } else {
+                applyCurrentBackgroundBounds();
+            }
+            updateSrcDrawing();
+        }
+    }
+
+    @Override
+    public void setAlpha(@FloatRange(from = 0.0, to = 1.0) float alpha) {
+        super.setAlpha(alpha);
+        setFadedOut(alpha != 1.0f);
+    }
+
     /**
      * A listener that is notified when some child locations might have changed.
      */
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 1b85016..fc2e95d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -151,7 +151,10 @@
 
     private static final int WINDOW_ID_UNKNOWN = -1;
 
-    private static int sIdCounter = 0;
+    // Each service has an ID. Also provide one for magnification gesture handling
+    public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0;
+
+    private static int sIdCounter = MAGNIFICATION_GESTURE_HANDLER_ID + 1;
 
     private static int sNextWindowId;
 
@@ -183,8 +186,6 @@
 
     private MagnificationController mMagnificationController;
 
-    private boolean mUnregisterMagnificationOnReset;
-
     private InteractionBridge mInteractionBridge;
 
     private AlertDialog mEnableTouchExplorationDialog;
@@ -784,11 +785,6 @@
             float scale, float centerX, float centerY) {
         synchronized (mLock) {
             notifyMagnificationChangedLocked(region, scale, centerX, centerY);
-
-            if (mUnregisterMagnificationOnReset && scale == 1.0f) {
-                mUnregisterMagnificationOnReset = false;
-                mMagnificationController.unregister();
-            }
         }
     }
 
@@ -1736,25 +1732,17 @@
     }
 
     private void updateMagnificationLocked(UserState userState) {
-        final int userId = userState.mUserId;
-        if (userId == mCurrentUserId && mMagnificationController != null) {
-            if (userState.mIsDisplayMagnificationEnabled ||
-                    userHasMagnificationServicesLocked(userState)) {
-                mMagnificationController.setUserId(userState.mUserId);
-            } else {
-                // If the user no longer has any magnification-controlling
-                // services and is not using magnification gestures, then
-                // reset the state to normal.
-                if (mMagnificationController.resetIfNeeded(true)) {
-                    // Animations are still running, so wait until we receive a
-                    // callback verifying that we've reset magnification.
-                    mUnregisterMagnificationOnReset = true;
-                } else {
-                    mUnregisterMagnificationOnReset = false;
-                    mMagnificationController.unregister();
-                    mMagnificationController = null;
-                }
-            }
+        if (userState.mUserId != mCurrentUserId) {
+            return;
+        }
+
+        if (userState.mIsDisplayMagnificationEnabled ||
+                userHasMagnificationServicesLocked(userState)) {
+            // Initialize the magnification controller if necessary
+            getMagnificationController();
+            mMagnificationController.register();
+        } else if (mMagnificationController != null) {
+            mMagnificationController.unregister();
         }
     }
 
@@ -2152,7 +2140,6 @@
         synchronized (mLock) {
             if (mMagnificationController == null) {
                 mMagnificationController = new MagnificationController(mContext, this, mLock);
-                mMagnificationController.register();
                 mMagnificationController.setUserId(mCurrentUserId);
             }
             return mMagnificationController;
@@ -2886,7 +2873,7 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 final Region region = Region.obtain();
-                getMagnificationController().getMagnifiedRegion(region);
+                getMagnificationController().getMagnificationRegion(region);
                 return region;
             } finally {
                 Binder.restoreCallingIdentity(identity);
@@ -2957,7 +2944,7 @@
             final long identity = Binder.clearCallingIdentity();
             try {
                 return getMagnificationController().setScaleAndCenter(
-                        scale, centerX, centerY, animate);
+                        scale, centerX, centerY, animate, mId);
             } finally {
                 Binder.restoreCallingIdentity(identity);
             }
@@ -3090,10 +3077,11 @@
                     userState.mInstalledServices.remove(mAccessibilityServiceInfo);
                     userState.mEnabledServices.remove(mComponentName);
                     userState.destroyUiAutomationService();
-                    if (readConfigurationForUserStateLocked(userState)) {
-                        onUserStateChangedLocked(userState);
-                    }
                 }
+                if (mId == getMagnificationController().getIdOfLastServiceToMagnify()) {
+                    getMagnificationController().resetIfNeeded(true);
+                }
+                onUserStateChangedLocked(userState);
             }
         }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
index f1b3722..027b6e2 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationController.java
@@ -17,6 +17,7 @@
 package com.android.server.accessibility;
 
 import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.os.SomeArgs;
 import com.android.server.LocalServices;
 
@@ -60,6 +61,8 @@
 
     private static final int DEFAULT_SCREEN_MAGNIFICATION_AUTO_UPDATE = 1;
 
+    private static final int INVALID_ID = -1;
+
     private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f;
 
     private static final float MIN_SCALE = 1.0f;
@@ -80,9 +83,8 @@
      */
     private final MagnificationSpec mCurrentMagnificationSpec = MagnificationSpec.obtain();
 
-    private final Region mMagnifiedRegion = Region.obtain();
-    private final Region mAvailableRegion = Region.obtain();
-    private final Rect mMagnifiedBounds = new Rect();
+    private final Region mMagnificationRegion = Region.obtain();
+    private final Rect mMagnificationBounds = new Rect();
 
     private final Rect mTempRect = new Rect();
     private final Rect mTempRect1 = new Rect();
@@ -97,35 +99,67 @@
 
     private int mUserId;
 
+    private int mIdOfLastServiceToMagnify = INVALID_ID;
+
+    // Flag indicating that we are registered with window manager.
+    private boolean mRegistered;
+
+    private boolean mUnregisterPending;
+
     public MagnificationController(Context context, AccessibilityManagerService ams, Object lock) {
         mAms = ams;
         mContentResolver = context.getContentResolver();
         mScreenStateObserver = new ScreenStateObserver(context, this);
         mWindowStateObserver = new WindowStateObserver(context, this);
-        mSpecAnimationBridge = new SpecAnimationBridge(context);
         mLock = lock;
+        mSpecAnimationBridge = new SpecAnimationBridge(context, mLock);
     }
 
     /**
-     * Registers magnification-related observers.
+     * Start tracking the magnification region for services that control magnification and the
+     * magnification gesture handler.
+     *
+     * This tracking imposes a cost on the system, so we avoid tracking this data
+     * unless it's required.
      */
     public void register() {
-        mScreenStateObserver.register();
-        mWindowStateObserver.register();
-
-        // Obtain initial state.
-        mWindowStateObserver.getRegions(mMagnifiedRegion, mAvailableRegion);
-        mMagnifiedRegion.getBounds(mMagnifiedBounds);
+        synchronized (mLock) {
+            if (!mRegistered) {
+                mScreenStateObserver.register();
+                mWindowStateObserver.register();
+                mSpecAnimationBridge.setEnabled(true);
+                // Obtain initial state.
+                mWindowStateObserver.getMagnificationRegion(mMagnificationRegion);
+                mMagnificationRegion.getBounds(mMagnificationBounds);
+                mRegistered = true;
+            }
+        }
     }
 
     /**
-     * Unregisters magnification-related observers.
+     * Stop requiring tracking the magnification region. We may remain registered while we
+     * reset magnification.
      */
     public void unregister() {
-        mSpecAnimationBridge.cancel();
+        synchronized (mLock) {
+            if (!isMagnifying()) {
+                unregisterInternalLocked();
+            } else {
+                mUnregisterPending = true;
+                resetLocked(true);
+            }
+        }
+    }
 
-        mScreenStateObserver.unregister();
-        mWindowStateObserver.unregister();
+    private void unregisterInternalLocked() {
+        if (mRegistered) {
+            mSpecAnimationBridge.setEnabled(false);
+            mScreenStateObserver.unregister();
+            mWindowStateObserver.unregister();
+            mMagnificationRegion.setEmpty();
+            mRegistered = false;
+        }
+        mUnregisterPending = false;
     }
 
     /**
@@ -137,24 +171,22 @@
     }
 
     /**
-     * Sets the magnified and available regions.
+     * Update our copy of the current magnification region
      *
      * @param magnified the magnified region
-     * @param available the region available for magnification
      * @param updateSpec {@code true} to update the scale and center based on
      *                   the region bounds, {@code false} to leave them as-is
      */
-    private void setMagnifiedRegion(Region magnified, Region available, boolean updateSpec) {
+    private void onMagnificationRegionChanged(Region magnified, boolean updateSpec) {
         synchronized (mLock) {
             boolean magnificationChanged = false;
             boolean boundsChanged = false;
 
-            if (!mMagnifiedRegion.equals(magnified)) {
-                mMagnifiedRegion.set(magnified);
-                mMagnifiedRegion.getBounds(mMagnifiedBounds);
+            if (!mMagnificationRegion.equals(magnified)) {
+                mMagnificationRegion.set(magnified);
+                mMagnificationRegion.getBounds(mMagnificationBounds);
                 boundsChanged = true;
             }
-            mAvailableRegion.set(available);
             if (updateSpec) {
                 final MagnificationSpec sentSpec = mSpecAnimationBridge.mSentMagnificationSpec;
                 final float scale = sentSpec.scale;
@@ -162,12 +194,12 @@
                 final float offsetY = sentSpec.offsetY;
 
                 // Compute the new center and update spec as needed.
-                final float centerX = (mMagnifiedBounds.width() / 2.0f
-                        + mMagnifiedBounds.left - offsetX) / scale;
-                final float centerY = (mMagnifiedBounds.height() / 2.0f
-                        + mMagnifiedBounds.top - offsetY) / scale;
+                final float centerX = (mMagnificationBounds.width() / 2.0f
+                        + mMagnificationBounds.left - offsetX) / scale;
+                final float centerY = (mMagnificationBounds.height() / 2.0f
+                        + mMagnificationBounds.top - offsetY) / scale;
                 magnificationChanged = setScaleAndCenterLocked(
-                        scale, centerX, centerY, false);
+                        scale, centerX, centerY, false, INVALID_ID);
             }
 
             // If magnification changed we already notified for the change.
@@ -178,7 +210,7 @@
     }
 
     /**
-     * Returns whether the magnified region contains the specified
+     * Returns whether the magnification region contains the specified
      * screen-relative coordinates.
      *
      * @param x the screen-relative X coordinate to check
@@ -186,51 +218,36 @@
      * @return {@code true} if the coordinate is contained within the
      *         magnified region, or {@code false} otherwise
      */
-    public boolean magnifiedRegionContains(float x, float y) {
+    public boolean magnificationRegionContains(float x, float y) {
         synchronized (mLock) {
-            return mMagnifiedRegion.contains((int) x, (int) y);
-        }
-    }
-
-    /**
-     * Returns whether the region available for magnification contains the
-     * specified screen-relative coordinates.
-     *
-     * @param x the screen-relative X coordinate to check
-     * @param y the screen-relative Y coordinate to check
-     * @return {@code true} if the coordinate is contained within the
-     *         region available for magnification, or {@code false} otherwise
-     */
-    private boolean availableRegionContains(float x, float y) {
-        synchronized (mLock) {
-            return mAvailableRegion.contains((int) x, (int) y);
+            return mMagnificationRegion.contains((int) x, (int) y);
         }
     }
 
     /**
      * Populates the specified rect with the screen-relative bounds of the
-     * magnified region. If magnification is not enabled, the returned
+     * magnification region. If magnification is not enabled, the returned
      * bounds will be empty.
      *
      * @param outBounds rect to populate with the bounds of the magnified
      *                  region
      */
-    public void getMagnifiedBounds(@NonNull Rect outBounds) {
+    public void getMagnificationBounds(@NonNull Rect outBounds) {
         synchronized (mLock) {
-            outBounds.set(mMagnifiedBounds);
+            outBounds.set(mMagnificationBounds);
         }
     }
 
     /**
-     * Populates the specified region with the screen-relative magnified
+     * Populates the specified region with the screen-relative magnification
      * region. If magnification is not enabled, then the returned region
      * will be empty.
      *
      * @param outRegion the region to populate
      */
-    public void getMagnifiedRegion(@NonNull Region outRegion) {
+    public void getMagnificationRegion(@NonNull Region outRegion) {
         synchronized (mLock) {
-            outRegion.set(mMagnifiedRegion);
+            outRegion.set(mMagnificationRegion);
         }
     }
 
@@ -263,8 +280,8 @@
      */
     public float getCenterX() {
         synchronized (mLock) {
-            return  (mMagnifiedBounds.width() / 2.0f
-                    + mMagnifiedBounds.left - getOffsetX()) / getScale();
+            return (mMagnificationBounds.width() / 2.0f
+                    + mMagnificationBounds.left - getOffsetX()) / getScale();
         }
     }
 
@@ -286,8 +303,8 @@
      */
     public float getCenterY() {
         synchronized (mLock) {
-            return (mMagnifiedBounds.height() / 2.0f
-                    + mMagnifiedBounds.top - getOffsetY()) / getScale();
+            return (mMagnificationBounds.height() / 2.0f
+                    + mMagnificationBounds.top - getOffsetY()) / getScale();
         }
     }
 
@@ -335,17 +352,25 @@
      */
     public boolean reset(boolean animate) {
         synchronized (mLock) {
-            final MagnificationSpec spec = mCurrentMagnificationSpec;
-            final boolean changed = !spec.isNop();
-            if (changed) {
-                spec.clear();
-                onMagnificationChangedLocked();
-            }
-            mSpecAnimationBridge.updateSentSpec(spec, animate);
-            return changed;
+            return resetLocked(animate);
         }
     }
 
+    private boolean resetLocked(boolean animate) {
+        if (!mRegistered) {
+            return false;
+        }
+        final MagnificationSpec spec = mCurrentMagnificationSpec;
+        final boolean changed = !spec.isNop();
+        if (changed) {
+            spec.clear();
+            onMagnificationChangedLocked();
+        }
+        mIdOfLastServiceToMagnify = INVALID_ID;
+        mSpecAnimationBridge.updateSentSpec(spec, animate);
+        return changed;
+    }
+
     /**
      * Scales the magnified region around the specified pivot point,
      * optionally animating the transition. If animation is disabled, the
@@ -356,16 +381,20 @@
      * @param pivotY the screen-relative Y coordinate around which to scale
      * @param animate {@code true} to animate the transition, {@code false}
      *                to transition immediately
+     * @param id the ID of the service requesting the change
      * @return {@code true} if the magnification spec changed, {@code false} if
      *         the spec did not change
      */
-    public boolean setScale(float scale, float pivotX, float pivotY, boolean animate) {
+    public boolean setScale(float scale, float pivotX, float pivotY, boolean animate, int id) {
         synchronized (mLock) {
+            if (!mRegistered) {
+                return false;
+            }
             // Constrain scale immediately for use in the pivot calculations.
             scale = MathUtils.constrain(scale, MIN_SCALE, MAX_SCALE);
 
             final Rect viewport = mTempRect;
-            mMagnifiedRegion.getBounds(viewport);
+            mMagnificationRegion.getBounds(viewport);
             final MagnificationSpec spec = mCurrentMagnificationSpec;
             final float oldScale = spec.scale;
             final float oldCenterX = (viewport.width() / 2.0f - spec.offsetX) / oldScale;
@@ -376,7 +405,8 @@
             final float offsetY = (oldCenterY - normPivotY) * (oldScale / scale);
             final float centerX = normPivotX + offsetX;
             final float centerY = normPivotY + offsetY;
-            return setScaleAndCenterLocked(scale, centerX, centerY, animate);
+            mIdOfLastServiceToMagnify = id;
+            return setScaleAndCenterLocked(scale, centerX, centerY, animate, id);
         }
     }
 
@@ -390,12 +420,16 @@
      *                center
      * @param animate {@code true} to animate the transition, {@code false}
      *                to transition immediately
+     * @param id the ID of the service requesting the change
      * @return {@code true} if the magnification spec changed, {@code false} if
      *         the spec did not change
      */
-    public boolean setCenter(float centerX, float centerY, boolean animate) {
+    public boolean setCenter(float centerX, float centerY, boolean animate, int id) {
         synchronized (mLock) {
-            return setScaleAndCenterLocked(Float.NaN, centerX, centerY, animate);
+            if (!mRegistered) {
+                return false;
+            }
+            return setScaleAndCenterLocked(Float.NaN, centerX, centerY, animate, id);
         }
     }
 
@@ -411,19 +445,27 @@
      *                center and scale, or {@link Float#NaN} to leave unchanged
      * @param animate {@code true} to animate the transition, {@code false}
      *                to transition immediately
+     * @param id the ID of the service requesting the change
      * @return {@code true} if the magnification spec changed, {@code false} if
      *         the spec did not change
      */
-    public boolean setScaleAndCenter(float scale, float centerX, float centerY, boolean animate) {
+    public boolean setScaleAndCenter(
+            float scale, float centerX, float centerY, boolean animate, int id) {
         synchronized (mLock) {
-            return setScaleAndCenterLocked(scale, centerX, centerY, animate);
+            if (!mRegistered) {
+                return false;
+            }
+            return setScaleAndCenterLocked(scale, centerX, centerY, animate, id);
         }
     }
 
     private boolean setScaleAndCenterLocked(float scale, float centerX, float centerY,
-            boolean animate) {
+            boolean animate, int id) {
         final boolean changed = updateMagnificationSpecLocked(scale, centerX, centerY);
         mSpecAnimationBridge.updateSentSpec(mCurrentMagnificationSpec, animate);
+        if (isMagnifying() && (id != INVALID_ID)) {
+            mIdOfLastServiceToMagnify = id;
+        }
         return changed;
     }
 
@@ -432,22 +474,42 @@
      *
      * @param offsetX the amount in pixels to offset the X center
      * @param offsetY the amount in pixels to offset the Y center
+     * @param id the ID of the service requesting the change
      */
-    public void offsetMagnifiedRegionCenter(float offsetX, float offsetY) {
+    public void offsetMagnifiedRegionCenter(float offsetX, float offsetY, int id) {
         synchronized (mLock) {
+            if (!mRegistered) {
+                return;
+            }
+
             final MagnificationSpec currSpec = mCurrentMagnificationSpec;
             final float nonNormOffsetX = currSpec.offsetX - offsetX;
             currSpec.offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
             final float nonNormOffsetY = currSpec.offsetY - offsetY;
             currSpec.offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0);
+            if (id != INVALID_ID) {
+                mIdOfLastServiceToMagnify = id;
+            }
             mSpecAnimationBridge.updateSentSpec(currSpec, false);
         }
     }
 
+    /**
+     * Get the ID of the last service that changed the magnification spec.
+     *
+     * @return The id
+     */
+    public int getIdOfLastServiceToMagnify() {
+        return mIdOfLastServiceToMagnify;
+    }
+
     private void onMagnificationChangedLocked() {
         mAms.onMagnificationStateChanged();
-        mAms.notifyMagnificationChanged(mMagnifiedRegion,
+        mAms.notifyMagnificationChanged(mMagnificationRegion,
                 getScale(), getCenterX(), getCenterY());
+        if (mUnregisterPending && !isMagnifying()) {
+            unregisterInternalLocked();
+        }
     }
 
     /**
@@ -503,8 +565,8 @@
             scale = getScale();
         }
 
-        // Ensure requested center is within the available region.
-        if (!availableRegionContains(centerX, centerY)) {
+        // Ensure requested center is within the magnification region.
+        if (!magnificationRegionContains(centerX, centerY)) {
             return false;
         }
 
@@ -518,16 +580,16 @@
             changed = true;
         }
 
-        final float nonNormOffsetX = mMagnifiedBounds.width() / 2.0f
-                + mMagnifiedBounds.left - centerX * scale;
+        final float nonNormOffsetX = mMagnificationBounds.width() / 2.0f
+                + mMagnificationBounds.left - centerX * scale;
         final float offsetX = MathUtils.constrain(nonNormOffsetX, getMinOffsetXLocked(), 0);
         if (Float.compare(currSpec.offsetX, offsetX) != 0) {
             currSpec.offsetX = offsetX;
             changed = true;
         }
 
-        final float nonNormOffsetY = mMagnifiedBounds.height() / 2.0f
-                + mMagnifiedBounds.top - centerY * scale;
+        final float nonNormOffsetY = mMagnificationBounds.height() / 2.0f
+                + mMagnificationBounds.top - centerY * scale;
         final float offsetY = MathUtils.constrain(nonNormOffsetY, getMinOffsetYLocked(), 0);
         if (Float.compare(currSpec.offsetY, offsetY) != 0) {
             currSpec.offsetY = offsetY;
@@ -542,12 +604,12 @@
     }
 
     private float getMinOffsetXLocked() {
-        final float viewportWidth = mMagnifiedBounds.width();
+        final float viewportWidth = mMagnificationBounds.width();
         return viewportWidth - viewportWidth * mCurrentMagnificationSpec.scale;
     }
 
     private float getMinOffsetYLocked() {
-        final float viewportHeight = mMagnifiedBounds.height();
+        final float viewportHeight = mMagnificationBounds.height();
         return viewportHeight - viewportHeight * mCurrentMagnificationSpec.scale;
     }
 
@@ -595,7 +657,7 @@
         final float scale = getSentScale();
         final float offsetX = getSentOffsetX();
         final float offsetY = getSentOffsetY();
-        getMagnifiedBounds(outFrame);
+        getMagnificationBounds(outFrame);
         outFrame.offset((int) -offsetX, (int) -offsetY);
         outFrame.scale(1.0f / scale);
     }
@@ -603,7 +665,7 @@
     private void requestRectangleOnScreen(int left, int top, int right, int bottom) {
         synchronized (mLock) {
             final Rect magnifiedFrame = mTempRect;
-            getMagnifiedBounds(magnifiedFrame);
+            getMagnificationBounds(magnifiedFrame);
             if (!magnifiedFrame.intersects(left, top, right, bottom)) {
                 return;
             }
@@ -640,7 +702,7 @@
             }
 
             final float scale = getScale();
-            offsetMagnifiedRegionCenter(scrollX * scale, scrollY * scale);
+            offsetMagnifiedRegionCenter(scrollX * scale, scrollY * scale, INVALID_ID);
         }
     }
 
@@ -656,7 +718,7 @@
 
         /**
          * The magnification spec that was sent to the window manager. This should
-         * only be accessed and modified on the main (e.g. animation) thread.
+         * only be accessed with the lock held.
          */
         private final MagnificationSpec mSentMagnificationSpec = MagnificationSpec.obtain();
 
@@ -667,8 +729,13 @@
         private final ValueAnimator mTransformationAnimator;
 
         private final long mMainThreadId;
+        private final Object mLock;
 
-        private SpecAnimationBridge(Context context) {
+        @GuardedBy("mLock")
+        private boolean mEnabled = false;
+
+        private SpecAnimationBridge(Context context, Object lock) {
+            mLock = lock;
             final Looper mainLooper = context.getMainLooper();
             mMainThreadId = mainLooper.getThread().getId();
 
@@ -685,9 +752,19 @@
             mTransformationAnimator.setInterpolator(new DecelerateInterpolator(2.5f));
         }
 
-        public void cancel() {
-            if (mTransformationAnimator != null && mTransformationAnimator.isRunning()) {
-                mTransformationAnimator.cancel();
+        /**
+         * Enabled means the bridge will accept input. When not enabled, the output of the animator
+         * will be ignored
+         */
+        public void setEnabled(boolean enabled) {
+            synchronized (mLock) {
+                if (enabled != mEnabled) {
+                    mEnabled = enabled;
+                    if (!mEnabled) {
+                        mSentMagnificationSpec.clear();
+                        mWindowManager.setMagnificationSpec(mSentMagnificationSpec);
+                    }
+                }
             }
         }
 
@@ -710,28 +787,32 @@
             }
 
             // If the current and sent specs don't match, update the sent spec.
-            final boolean changed = !mSentMagnificationSpec.equals(spec);
-            if (changed) {
-                if (animate) {
-                    animateMagnificationSpec(spec);
-                } else {
-                    setMagnificationSpec(spec);
+            synchronized (mLock) {
+                final boolean changed = !mSentMagnificationSpec.equals(spec);
+                if (changed) {
+                    if (animate) {
+                        animateMagnificationSpecLocked(spec);
+                    } else {
+                        setMagnificationSpecLocked(spec);
+                    }
                 }
             }
         }
 
-        private void animateMagnificationSpec(MagnificationSpec toSpec) {
+        private void animateMagnificationSpecLocked(MagnificationSpec toSpec) {
             mTransformationAnimator.setObjectValues(mSentMagnificationSpec, toSpec);
             mTransformationAnimator.start();
         }
 
-        private void setMagnificationSpec(MagnificationSpec spec) {
-            if (DEBUG_SET_MAGNIFICATION_SPEC) {
-                Slog.i(LOG_TAG, "Sending: " + spec);
-            }
+        private void setMagnificationSpecLocked(MagnificationSpec spec) {
+            if (mEnabled) {
+                if (DEBUG_SET_MAGNIFICATION_SPEC) {
+                    Slog.i(LOG_TAG, "Sending: " + spec);
+                }
 
-            mSentMagnificationSpec.setTo(spec);
-            mWindowManager.setMagnificationSpec(spec);
+                mSentMagnificationSpec.setTo(spec);
+                mWindowManager.setMagnificationSpec(spec);
+            }
         }
 
         private class UpdateHandler extends Handler {
@@ -759,12 +840,16 @@
 
             @Override
             public MagnificationSpec get(SpecAnimationBridge object) {
-                return object.mSentMagnificationSpec;
+                synchronized (object.mLock) {
+                    return object.mSentMagnificationSpec;
+                }
             }
 
             @Override
             public void set(SpecAnimationBridge object, MagnificationSpec value) {
-                object.setMagnificationSpec(value);
+                synchronized (object.mLock) {
+                    object.setMagnificationSpecLocked(value);
+                }
             }
         }
 
@@ -862,15 +947,14 @@
         }
 
         @Override
-        public void onMagnifiedBoundsChanged(Region magnified, Region available) {
+        public void onMagnificationRegionChanged(Region magnificationRegion) {
             final SomeArgs args = SomeArgs.obtain();
-            args.arg1 = Region.obtain(magnified);
-            args.arg2 = Region.obtain(available);
+            args.arg1 = Region.obtain(magnificationRegion);
             mHandler.obtainMessage(MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
         }
 
-        private void handleOnMagnifiedBoundsChanged(Region magnified, Region available) {
-            mController.setMagnifiedRegion(magnified, available, mSpecIsDirty);
+        private void handleOnMagnifiedBoundsChanged(Region magnificationRegion) {
+            mController.onMagnificationRegionChanged(magnificationRegion, mSpecIsDirty);
             mSpecIsDirty = false;
         }
 
@@ -911,8 +995,15 @@
             mController.resetIfNeeded(true);
         }
 
-        public void getRegions(@NonNull Region outMagnified, @NonNull Region outAvailable) {
-            mWindowManager.getMagnificationRegions(outMagnified, outAvailable);
+        /**
+         * This method is used to get the magnification region in the tiny time slice between
+         * registering the callbacks and handling the message.
+         * TODO: Elimiante this extra path, perhaps by processing the message immediately
+         *
+         * @param outMagnificationRegion
+         */
+        public void getMagnificationRegion(@NonNull Region outMagnificationRegion) {
+            mWindowManager.getMagnificationRegion(outMagnificationRegion);
         }
 
         private class CallbackHandler extends Handler {
@@ -926,10 +1017,8 @@
                     case MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED: {
                         final SomeArgs args = (SomeArgs) message.obj;
                         final Region magnifiedBounds = (Region) args.arg1;
-                        final Region availableBounds = (Region) args.arg2;
-                        handleOnMagnifiedBoundsChanged(magnifiedBounds, availableBounds);
+                        handleOnMagnifiedBoundsChanged(magnifiedBounds);
                         magnifiedBounds.recycle();
-                        availableBounds.recycle();
                     } break;
                     case MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED: {
                         final SomeArgs args = (SomeArgs) message.obj;
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 818ac81..39bc809 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -237,7 +237,7 @@
         final float eventX = event.getX();
         final float eventY = event.getY();
         if (mMagnificationController.isMagnifying()
-                && mMagnificationController.magnifiedRegionContains(eventX, eventY)) {
+                && mMagnificationController.magnificationRegionContains(eventX, eventY)) {
             final float scale = mMagnificationController.getScale();
             final float scaledOffsetX = mMagnificationController.getOffsetX();
             final float scaledOffsetY = mMagnificationController.getOffsetY();
@@ -381,7 +381,8 @@
                 Slog.i(LOG_TAG, "Panned content by scrollX: " + distanceX
                         + " scrollY: " + distanceY);
             }
-            mMagnificationController.offsetMagnifiedRegionCenter(distanceX, distanceY);
+            mMagnificationController.offsetMagnifiedRegionCenter(distanceX, distanceY,
+                    AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
             return true;
         }
 
@@ -421,7 +422,8 @@
 
             final float pivotX = detector.getFocusX();
             final float pivotY = detector.getFocusY();
-            mMagnificationController.setScale(scale, pivotX, pivotY, false);
+            mMagnificationController.setScale(scale, pivotX, pivotY, false,
+                    AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
             return true;
         }
 
@@ -469,14 +471,14 @@
                     }
                     final float eventX = event.getX();
                     final float eventY = event.getY();
-                    if (mMagnificationController.magnifiedRegionContains(eventX, eventY)) {
+                    if (mMagnificationController.magnificationRegionContains(eventX, eventY)) {
                         if (mLastMoveOutsideMagnifiedRegion) {
                             mLastMoveOutsideMagnifiedRegion = false;
-                            mMagnificationController.setCenter(eventX,
-                                    eventY, true);
+                            mMagnificationController.setCenter(eventX, eventY, true,
+                                    AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
                         } else {
-                            mMagnificationController.setCenter(eventX,
-                                    eventY, false);
+                            mMagnificationController.setCenter(eventX, eventY, false,
+                                    AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
                         }
                     } else {
                         mLastMoveOutsideMagnifiedRegion = true;
@@ -571,7 +573,7 @@
             switch (action) {
                 case MotionEvent.ACTION_DOWN: {
                     mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
-                    if (!mMagnificationController.magnifiedRegionContains(
+                    if (!mMagnificationController.magnificationRegionContains(
                             event.getX(), event.getY())) {
                         transitionToDelegatingStateAndClear();
                         return;
@@ -616,7 +618,7 @@
                         return;
                     }
                     mHandler.removeMessages(MESSAGE_ON_ACTION_TAP_AND_HOLD);
-                    if (!mMagnificationController.magnifiedRegionContains(
+                    if (!mMagnificationController.magnificationRegionContains(
                             event.getX(), event.getY())) {
                         transitionToDelegatingStateAndClear();
                         return;
@@ -726,7 +728,8 @@
             if (!mMagnificationController.isMagnifying()) {
                 final float targetScale = mMagnificationController.getPersistedScale();
                 final float scale = MathUtils.constrain(targetScale, MIN_SCALE, MAX_SCALE);
-                mMagnificationController.setScaleAndCenter(scale, up.getX(), up.getY(), true);
+                mMagnificationController.setScaleAndCenter(scale, up.getX(), up.getY(), true,
+                        AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
             } else {
                 mMagnificationController.reset(true);
             }
@@ -742,7 +745,8 @@
 
             final float targetScale = mMagnificationController.getPersistedScale();
             final float scale = MathUtils.constrain(targetScale, MIN_SCALE, MAX_SCALE);
-            mMagnificationController.setScaleAndCenter(scale, down.getX(), down.getY(), true);
+            mMagnificationController.setScaleAndCenter(scale, down.getX(), down.getY(), true,
+                    AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
 
             transitionToState(STATE_VIEWPORT_DRAGGING);
         }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index f06583b..0287332 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -31,7 +31,6 @@
 import static android.net.NetworkPolicyManager.RULE_ALLOW_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_ALL;
 import static android.net.NetworkPolicyManager.RULE_REJECT_METERED;
-
 import android.annotation.Nullable;
 import android.app.BroadcastOptions;
 import android.app.Notification;
@@ -1382,6 +1381,10 @@
             if (LOGD_RULES) {
                 log("onRestrictBackgroundChanged(restrictBackground=" + restrictBackground + ")");
             }
+            if (restrictBackground) {
+                log("onRestrictBackgroundChanged(true): disabling tethering");
+                mTethering.untetherAll();
+            }
         }
 
         @Override
@@ -1813,6 +1816,14 @@
         pw.decreaseIndent();
         pw.println();
 
+        pw.println("Metered Interfaces:");
+        pw.increaseIndent();
+        for (String value : mMeteredIfaces) {
+            pw.println(value);
+        }
+        pw.decreaseIndent();
+        pw.println();
+
         pw.println("Network Requests:");
         pw.increaseIndent();
         for (NetworkRequestInfo nri : mNetworkRequests.values()) {
@@ -2568,7 +2579,14 @@
     public int tether(String iface) {
         ConnectivityManager.enforceTetherChangePermission(mContext);
         if (isTetheringSupported()) {
-            return mTethering.tether(iface);
+            final int status = mTethering.tether(iface);
+            if (status == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                try {
+                    mPolicyManager.onTetheringChanged(iface, true);
+                } catch (RemoteException e) {
+                }
+            }
+            return status;
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
         }
@@ -2579,7 +2597,14 @@
         ConnectivityManager.enforceTetherChangePermission(mContext);
 
         if (isTetheringSupported()) {
-            return mTethering.untether(iface);
+            final int status = mTethering.untether(iface);
+            if (status == ConnectivityManager.TETHER_ERROR_NO_ERROR) {
+                try {
+                    mPolicyManager.onTetheringChanged(iface, false);
+                } catch (RemoteException e) {
+                }
+            }
+            return status;
         } else {
             return ConnectivityManager.TETHER_ERROR_UNSUPPORTED;
         }
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 2516f5d..c6786de 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -79,7 +79,8 @@
  * battery life.
  */
 public final class BatteryStatsService extends IBatteryStats.Stub
-        implements PowerManagerInternal.LowPowerModeListener {
+        implements PowerManagerInternal.LowPowerModeListener,
+        BatteryStatsImpl.PlatformIdleStateCallback {
     static final String TAG = "BatteryStatsService";
 
     /**
@@ -173,6 +174,33 @@
         }
     }
 
+    private native int getPlatformLowPowerStats(ByteBuffer outBuffer);
+    private CharsetDecoder mDecoderStat = StandardCharsets.UTF_8
+                    .newDecoder()
+                    .onMalformedInput(CodingErrorAction.REPLACE)
+                    .onUnmappableCharacter(CodingErrorAction.REPLACE)
+                    .replaceWith("?");
+    private ByteBuffer mUtf8BufferStat = ByteBuffer.allocateDirect(MAX_LOW_POWER_STATS_SIZE);
+    private CharBuffer mUtf16BufferStat = CharBuffer.allocate(MAX_LOW_POWER_STATS_SIZE);
+    private static final int MAX_LOW_POWER_STATS_SIZE = 512;
+
+    @Override
+    public String getPlatformLowPowerStats() {
+        mUtf8BufferStat.clear();
+        mUtf16BufferStat.clear();
+        mDecoderStat.reset();
+        int bytesWritten = getPlatformLowPowerStats(mUtf8BufferStat);
+        if (bytesWritten < 0) {
+            return null;
+        } else if (bytesWritten == 0) {
+            return "Empty";
+        }
+        mUtf8BufferStat.limit(bytesWritten);
+        mDecoderStat.decode(mUtf8BufferStat, mUtf16BufferStat, true);
+        mUtf16BufferStat.flip();
+        return mUtf16BufferStat.toString();
+    }
+
     BatteryStatsService(File systemDir, Handler handler) {
         // Our handler here will be accessing the disk, use a different thread than
         // what the ActivityManagerService gave us (no I/O on that one!).
@@ -182,9 +210,9 @@
         mHandler = new BatteryStatsHandler(thread.getLooper());
 
         // BatteryStatsImpl expects the ActivityManagerService handler, so pass that one through.
-        mStats = new BatteryStatsImpl(systemDir, handler, mHandler);
+        mStats = new BatteryStatsImpl(systemDir, handler, mHandler, this);
     }
-    
+
     public void publish(Context context) {
         mContext = context;
         mStats.setRadioScanningTimeout(mContext.getResources().getInteger(
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 75d49c3..cdb68d8 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -220,6 +220,7 @@
 
     private void finishUserBoot(UserState uss, IIntentReceiver resultTo) {
         final int userId = uss.mHandle.getIdentifier();
+        Slog.d(TAG, "Finishing user boot " + userId);
         synchronized (mService) {
             // Bail if we ended up with a stale user
             if (mStartedUsers.get(userId) != uss) return;
@@ -248,7 +249,8 @@
                             + "): attempting unlock because parent is unlocked");
                     maybeUnlockUser(userId);
                 } else {
-                    Slog.d(TAG, "User " + userId + " (parent " + parent.id
+                    String parentId = (parent == null) ? "<null>" : String.valueOf(parent.id);
+                    Slog.d(TAG, "User " + userId + " (parent " + parentId
                             + "): delaying unlock because parent is locked");
                 }
             } else {
@@ -333,6 +335,10 @@
         synchronized (mService) {
             // Bail if we ended up with a stale user
             if (mStartedUsers.get(uss.mHandle.getIdentifier()) != uss) return;
+            final UserInfo userInfo = getUserInfo(userId);
+            if (userInfo == null) {
+                return;
+            }
 
             // Only keep marching forward if user is actually unlocked
             if (!isUserKeyUnlocked(userId)) return;
@@ -341,6 +347,25 @@
                 // Remember that we logged in
                 mUserManager.onUserLoggedIn(userId);
 
+                if (!userInfo.isInitialized()) {
+                    if (userId != UserHandle.USER_SYSTEM) {
+                        Slog.d(TAG, "Initializing user #" + userId);
+                        Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
+                        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+                        mService.broadcastIntentLocked(null, null, intent, null,
+                                new IIntentReceiver.Stub() {
+                                    @Override
+                                    public void performReceive(Intent intent, int resultCode,
+                                            String data, Bundle extras, boolean ordered,
+                                            boolean sticky, int sendingUser) {
+                                        // Note: performReceive is called with mService lock held
+                                        getUserManager().makeInitialized(userInfo.id);
+                                    }
+                                }, 0, null, null, null, AppOpsManager.OP_NONE,
+                                null, true, false, MY_PID, SYSTEM_UID, userId);
+                    }
+                }
+                Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId);
                 final Intent bootIntent = new Intent(Intent.ACTION_BOOT_COMPLETED, null);
                 bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
                 bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
@@ -669,6 +694,35 @@
         }
     }
 
+    /**
+     * Start user, if its not already running.
+     * <p>The user will be brought to the foreground, if {@code foreground} parameter is set.
+     * When starting the user, multiple intents will be broadcast in the following order:</p>
+     * <ul>
+     *     <li>{@link Intent#ACTION_USER_STARTED} - sent to registered receivers of the new user
+     *     <li>{@link Intent#ACTION_USER_BACKGROUND} - sent to registered receivers of the outgoing
+     *     user and all profiles of this user. Sent only if {@code foreground} parameter is true
+     *     <li>{@link Intent#ACTION_USER_FOREGROUND} - sent to registered receivers of the new
+     *     user and all profiles of this user. Sent only if {@code foreground} parameter is true
+     *     <li>{@link Intent#ACTION_USER_SWITCHED} - sent to registered receivers of the new user.
+     *     Sent only if {@code foreground} parameter is true
+     *     <li>{@link Intent#ACTION_USER_STARTING} - ordered broadcast sent to registered receivers
+     *     of the new fg user
+     *     <li>{@link Intent#ACTION_LOCKED_BOOT_COMPLETED} - ordered broadcast sent to receivers of
+     *     the new user
+     *     <li>{@link Intent#ACTION_USER_UNLOCKED} - sent to registered receivers of the new user
+     *     <li>{@link Intent#ACTION_PRE_BOOT_COMPLETED} - ordered broadcast sent to receivers of the
+     *     new user. Sent only when the user is booting after a system update.
+     *     <li>{@link Intent#ACTION_USER_INITIALIZE} - ordered broadcast sent to receivers of the
+     *     new user. Sent only the first time a user is starting.
+     *     <li>{@link Intent#ACTION_BOOT_COMPLETED} - ordered broadcast sent to receivers of the new
+     *     user. Indicates that the user has finished booting.
+     * </ul>
+     *
+     * @param userId ID of the user to start
+     * @param foreground true if user should be brought to the foreground
+     * @return true if the user has been successfully started
+     */
     boolean startUser(final int userId, final boolean foreground) {
         if (mService.checkCallingPermission(INTERACT_ACROSS_USERS_FULL)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -680,7 +734,7 @@
             throw new SecurityException(msg);
         }
 
-        if (DEBUG_MU) Slog.i(TAG, "starting userid:" + userId + " fore:" + foreground);
+        Slog.i(TAG, "Starting userid:" + userId + " fg:" + foreground);
 
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -790,36 +844,8 @@
                             null, false, false, MY_PID, SYSTEM_UID, userId);
                 }
 
-                if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
-                    if (userId != UserHandle.USER_SYSTEM) {
-                        Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
-                        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
-                        mService.broadcastIntentLocked(null, null, intent, null,
-                                new IIntentReceiver.Stub() {
-                                    @Override
-                                    public void performReceive(Intent intent, int resultCode,
-                                            String data, Bundle extras, boolean ordered,
-                                            boolean sticky, int sendingUser) {
-                                        mHandler.post(new Runnable() {
-                                            @Override
-                                            public void run() {
-                                                onUserInitialized(uss, foreground,
-                                                        oldUserId, userId);
-                                            }
-                                        });
-                                    }
-                                }, 0, null, null, null, AppOpsManager.OP_NONE,
-                                null, true, false, MY_PID, SYSTEM_UID, userId);
-                        uss.initializing = true;
-                    } else {
-                        getUserManager().makeInitialized(userInfo.id);
-                    }
-                }
-
                 if (foreground) {
-                    if (!uss.initializing) {
-                        moveUserToForegroundLocked(uss, oldUserId, userId);
-                    }
+                    moveUserToForegroundLocked(uss, oldUserId, userId);
                 } else {
                     mService.mUserController.finishUserBoot(uss);
                 }
@@ -996,8 +1022,8 @@
         }
     }
 
-    void dispatchUserSwitch(final UserState uss, final int oldUserId,
-            final int newUserId) {
+    void dispatchUserSwitch(final UserState uss, final int oldUserId, final int newUserId) {
+        Slog.d(TAG, "Dispatch onUserSwitching oldUser #" + oldUserId + " newUser #" + newUserId);
         final int observerCount = mUserSwitchObservers.beginBroadcast();
         if (observerCount > 0) {
             final IRemoteCallback callback = new IRemoteCallback.Stub() {
@@ -1041,39 +1067,14 @@
     }
 
     void continueUserSwitch(UserState uss, int oldUserId, int newUserId) {
-        completeSwitchAndInitialize(uss, oldUserId, newUserId, false, true);
-    }
-
-    void onUserInitialized(UserState uss, boolean foreground, int oldUserId, int newUserId) {
+        Slog.d(TAG, "Continue user switch oldUser #" + oldUserId + ", newUser #" + newUserId);
         synchronized (mService) {
-            if (foreground) {
-                moveUserToForegroundLocked(uss, oldUserId, newUserId);
-            }
+            mService.mWindowManager.stopFreezingScreen();
         }
-        completeSwitchAndInitialize(uss, oldUserId, newUserId, true, false);
-    }
-
-    void completeSwitchAndInitialize(UserState uss, int oldUserId, int newUserId,
-            boolean clearInitializing, boolean clearSwitching) {
-        boolean unfrozen = false;
-        synchronized (mService) {
-            if (clearInitializing) {
-                uss.initializing = false;
-                getUserManager().makeInitialized(uss.mHandle.getIdentifier());
-            }
-            if (clearSwitching) {
-                uss.switching = false;
-            }
-            if (!uss.switching && !uss.initializing) {
-                mService.mWindowManager.stopFreezingScreen();
-                unfrozen = true;
-            }
-        }
-        if (unfrozen) {
-            mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
-            mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
-                    newUserId, 0));
-        }
+        uss.switching = false;
+        mHandler.removeMessages(REPORT_USER_SWITCH_COMPLETE_MSG);
+        mHandler.sendMessage(mHandler.obtainMessage(REPORT_USER_SWITCH_COMPLETE_MSG,
+                newUserId, 0));
         stopGuestOrEphemeralUserIfBackground();
         stopBackgroundUsersIfEnforced(oldUserId);
     }
diff --git a/services/core/java/com/android/server/am/UserState.java b/services/core/java/com/android/server/am/UserState.java
index 56abd95..952283e 100644
--- a/services/core/java/com/android/server/am/UserState.java
+++ b/services/core/java/com/android/server/am/UserState.java
@@ -54,7 +54,6 @@
     public int state = STATE_BOOTING;
     public int lastState = STATE_BOOTING;
     public boolean switching;
-    public boolean initializing;
 
     /**
      * The last time that a provider was reported to usage stats as being brought to important
@@ -103,7 +102,6 @@
         pw.print(prefix);
         pw.print("state="); pw.print(stateToString(state));
         if (switching) pw.print(" SWITCHING");
-        if (initializing) pw.print(" INITIALIZING");
         pw.println();
     }
 }
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index c2022d5..1012f9a 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -610,6 +610,13 @@
         return ConnectivityManager.TETHER_ERROR_NO_ERROR;
     }
 
+    public void untetherAll() {
+        if (DBG) Log.d(TAG, "Untethering " + mIfaces);
+        for (String iface : mIfaces.keySet()) {
+            untether(iface);
+        }
+    }
+
     public int getLastTetherError(String iface) {
         TetherInterfaceSM sm = null;
         synchronized (mPublicSync) {
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 43f47fa..0b1ece5 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -1899,6 +1899,18 @@
     }
 
     @Override
+    public void onTetheringChanged(String iface, boolean tethering) {
+        // No need to enforce permission because setRestrictBackground() will do it.
+        if (LOGD) Log.d(TAG, "onTetherStateChanged(" + iface + ", " + tethering + ")");
+        synchronized (mRulesLock) {
+            if (mRestrictBackground && tethering) {
+                Log.d(TAG, "Tethering on (" + iface +"); disable Data Saver");
+                setRestrictBackground(false);
+            }
+        }
+    }
+
+    @Override
     public void setRestrictBackground(boolean restrictBackground) {
         mContext.enforceCallingOrSelfPermission(MANAGE_NETWORK_POLICY, TAG);
         final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 3ef077b..101f56f 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -124,9 +124,9 @@
         }
     }
 
-    public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
+    public void getMagnificationRegionLocked(Region outMagnificationRegion) {
         if (mDisplayMagnifier != null) {
-            mDisplayMagnifier.getMagnificationRegionsLocked(outMagnified, outAvailable);
+            mDisplayMagnifier.getMagnificationRegionLocked(outMagnificationRegion);
         }
     }
 
@@ -400,8 +400,8 @@
             return spec;
         }
 
-        public void getMagnificationRegionsLocked(Region outMagnified, Region outAvailable) {
-            mMagnifedViewport.getBoundsLocked(outMagnified, outAvailable);
+        public void getMagnificationRegionLocked(Region outMagnificationRegion) {
+            mMagnifedViewport.getMagnificationRegionLocked(outMagnificationRegion);
         }
 
         public void destroyLocked() {
@@ -424,10 +424,8 @@
 
             private final Matrix mTempMatrix = new Matrix();
 
-            private final Region mMagnifiedBounds = new Region();
-            private final Region mAvailableBounds = new Region();
-            private final Region mOldMagnifiedBounds = new Region();
-            private final Region mOldAvailableBounds = new Region();
+            private final Region mMagnificationRegion = new Region();
+            private final Region mOldMagnificationRegion = new Region();
 
             private final Path mCircularPath;
 
@@ -463,10 +461,8 @@
                 recomputeBoundsLocked();
             }
 
-            public void getBoundsLocked(@NonNull Region outMagnified,
-                    @NonNull Region outAvailable) {
-                outMagnified.set(mMagnifiedBounds);
-                outAvailable.set(mAvailableBounds);
+            public void getMagnificationRegionLocked(@NonNull Region outMagnificationRegion) {
+                outMagnificationRegion.set(mMagnificationRegion);
             }
 
             public void updateMagnificationSpecLocked(MagnificationSpec spec) {
@@ -488,11 +484,12 @@
                 final int screenWidth = mTempPoint.x;
                 final int screenHeight = mTempPoint.y;
 
-                mMagnifiedBounds.set(0, 0, 0, 0);
-                mAvailableBounds.set(0, 0, screenWidth, screenHeight);
+                mMagnificationRegion.set(0, 0, 0, 0);
+                final Region availableBounds = mTempRegion1;
+                availableBounds.set(0, 0, screenWidth, screenHeight);
 
                 if (mCircularPath != null) {
-                    mAvailableBounds.setPath(mCircularPath, mAvailableBounds);
+                    availableBounds.setPath(mCircularPath, availableBounds);
                 }
 
                 Region nonMagnifiedBounds = mTempRegion4;
@@ -526,21 +523,21 @@
                             (int) windowFrame.right, (int) windowFrame.bottom);
                     // Only update new regions
                     Region portionOfWindowAlreadyAccountedFor = mTempRegion3;
-                    portionOfWindowAlreadyAccountedFor.set(mMagnifiedBounds);
+                    portionOfWindowAlreadyAccountedFor.set(mMagnificationRegion);
                     portionOfWindowAlreadyAccountedFor.op(nonMagnifiedBounds, Region.Op.UNION);
                     windowBounds.op(portionOfWindowAlreadyAccountedFor, Region.Op.DIFFERENCE);
 
                     if (mWindowManagerService.mPolicy.canMagnifyWindow(windowState.mAttrs.type)) {
-                        mMagnifiedBounds.op(windowBounds, Region.Op.UNION);
-                        mMagnifiedBounds.op(mAvailableBounds, Region.Op.INTERSECT);
+                        mMagnificationRegion.op(windowBounds, Region.Op.UNION);
+                        mMagnificationRegion.op(availableBounds, Region.Op.INTERSECT);
                     } else {
                         nonMagnifiedBounds.op(windowBounds, Region.Op.UNION);
-                        mAvailableBounds.op(windowBounds, Region.Op.DIFFERENCE);
+                        availableBounds.op(windowBounds, Region.Op.DIFFERENCE);
                     }
 
                     // Update accounted bounds
                     Region accountedBounds = mTempRegion2;
-                    accountedBounds.set(mMagnifiedBounds);
+                    accountedBounds.set(mMagnificationRegion);
                     accountedBounds.op(nonMagnifiedBounds, Region.Op.UNION);
                     accountedBounds.op(0, 0, screenWidth, screenHeight, Region.Op.INTERSECT);
 
@@ -556,43 +553,36 @@
 
                 visibleWindows.clear();
 
-                mMagnifiedBounds.op(mDrawBorderInset, mDrawBorderInset,
+                mMagnificationRegion.op(mDrawBorderInset, mDrawBorderInset,
                         screenWidth - mDrawBorderInset, screenHeight - mDrawBorderInset,
                         Region.Op.INTERSECT);
 
-                final boolean magnifiedChanged = !mOldMagnifiedBounds.equals(mMagnifiedBounds);
-                final boolean availableChanged = !mOldAvailableBounds.equals(mAvailableBounds);
-                if (magnifiedChanged || availableChanged) {
-                    if (magnifiedChanged) {
-                        mWindow.setBounds(mMagnifiedBounds);
-                        Rect dirtyRect = mTempRect1;
-                        if (mFullRedrawNeeded) {
-                            mFullRedrawNeeded = false;
-                            dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
-                                    screenWidth - mDrawBorderInset,
-                                    screenHeight - mDrawBorderInset);
-                            mWindow.invalidate(dirtyRect);
-                        } else {
-                            Region dirtyRegion = mTempRegion3;
-                            dirtyRegion.set(mMagnifiedBounds);
-                            dirtyRegion.op(mOldMagnifiedBounds, Region.Op.UNION);
-                            dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
-                            dirtyRegion.getBounds(dirtyRect);
-                            mWindow.invalidate(dirtyRect);
-                        }
-
-                        mOldMagnifiedBounds.set(mMagnifiedBounds);
+                final boolean magnifiedChanged =
+                        !mOldMagnificationRegion.equals(mMagnificationRegion);
+                if (magnifiedChanged) {
+                    mWindow.setBounds(mMagnificationRegion);
+                    final Rect dirtyRect = mTempRect1;
+                    if (mFullRedrawNeeded) {
+                        mFullRedrawNeeded = false;
+                        dirtyRect.set(mDrawBorderInset, mDrawBorderInset,
+                                screenWidth - mDrawBorderInset,
+                                screenHeight - mDrawBorderInset);
+                        mWindow.invalidate(dirtyRect);
+                    } else {
+                        final Region dirtyRegion = mTempRegion3;
+                        dirtyRegion.set(mMagnificationRegion);
+                        dirtyRegion.op(mOldMagnificationRegion, Region.Op.UNION);
+                        dirtyRegion.op(nonMagnifiedBounds, Region.Op.INTERSECT);
+                        dirtyRegion.getBounds(dirtyRect);
+                        mWindow.invalidate(dirtyRect);
                     }
 
-                    if (availableChanged) {
-                        mOldAvailableBounds.set(mAvailableBounds);
-                    }
-
+                    mOldMagnificationRegion.set(mMagnificationRegion);
                     final SomeArgs args = SomeArgs.obtain();
-                    args.arg1 = Region.obtain(mMagnifiedBounds);
-                    args.arg2 = Region.obtain(mAvailableBounds);
+                    args.arg1 = Region.obtain(mMagnificationRegion);
                     mHandler.obtainMessage(
-                            MyHandler.MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED, args).sendToTarget();
+                            MyHandler.MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED, args)
+                            .sendToTarget();
                 }
             }
 
@@ -616,14 +606,14 @@
             public void setMagnifiedRegionBorderShownLocked(boolean shown, boolean animate) {
                 if (shown) {
                     mFullRedrawNeeded = true;
-                    mOldMagnifiedBounds.set(0, 0, 0, 0);
+                    mOldMagnificationRegion.set(0, 0, 0, 0);
                 }
                 mWindow.setShown(shown, animate);
             }
 
             public void getMagnifiedFrameInContentCoordsLocked(Rect rect) {
                 MagnificationSpec spec = mMagnificationSpec;
-                mMagnifiedBounds.getBounds(rect);
+                mMagnificationRegion.getBounds(rect);
                 rect.offset((int) -spec.offsetX, (int) -spec.offsetY);
                 rect.scale(1.0f / spec.scale);
             }
@@ -886,7 +876,7 @@
         }
 
         private class MyHandler extends Handler {
-            public static final int MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED = 1;
+            public static final int MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED = 1;
             public static final int MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 2;
             public static final int MESSAGE_NOTIFY_USER_CONTEXT_CHANGED = 3;
             public static final int MESSAGE_NOTIFY_ROTATION_CHANGED = 4;
@@ -899,13 +889,11 @@
             @Override
             public void handleMessage(Message message) {
                 switch (message.what) {
-                    case MESSAGE_NOTIFY_MAGNIFIED_BOUNDS_CHANGED: {
+                    case MESSAGE_NOTIFY_MAGNIFICATION_REGION_CHANGED: {
                         final SomeArgs args = (SomeArgs) message.obj;
                         final Region magnifiedBounds = (Region) args.arg1;
-                        final Region availableBounds = (Region) args.arg2;
-                        mCallbacks.onMagnifiedBoundsChanged(magnifiedBounds, availableBounds);
+                        mCallbacks.onMagnificationRegionChanged(magnifiedBounds);
                         magnifiedBounds.recycle();
-                        availableBounds.recycle();
                     } break;
 
                     case MESSAGE_NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED: {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index cf415ff..6a20edb 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3625,8 +3625,7 @@
             // disregarding font scale, which should remain set to
             // the value of the previous configuration.
             mTempConfiguration.setToDefaults();
-            mTempConfiguration.fontScale = currentConfig.fontScale;
-            mTempConfiguration.uiMode = currentConfig.uiMode;
+            mTempConfiguration.updateFrom(currentConfig);
             computeScreenConfigurationLocked(mTempConfiguration);
             if (currentConfig.diff(mTempConfiguration) != 0) {
                 mWaitingForConfig = true;
@@ -3689,11 +3688,15 @@
         }
 
         synchronized(mWindowMap) {
-            mCurConfiguration = new Configuration(config);
             if (mWaitingForConfig) {
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
             }
+            boolean configChanged = mCurConfiguration.diff(config) != 0;
+            if (!configChanged) {
+                return null;
+            }
+            mCurConfiguration = new Configuration(config);
             return onConfigurationChanged();
         }
     }
@@ -8877,8 +8880,7 @@
 
         boolean configChanged = updateOrientationFromAppTokensLocked(false);
         mTempConfiguration.setToDefaults();
-        mTempConfiguration.fontScale = mCurConfiguration.fontScale;
-        mTempConfiguration.uiMode = mCurConfiguration.uiMode;
+        mTempConfiguration.updateFrom(mCurConfiguration);
         computeScreenConfigurationLocked(mTempConfiguration);
         configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0;
 
@@ -10975,12 +10977,10 @@
         }
 
         @Override
-        public void getMagnificationRegions(@NonNull Region outMagnified,
-                @NonNull Region outAvailable) {
+        public void getMagnificationRegion(@NonNull Region magnificationRegion) {
             synchronized (mWindowMap) {
                 if (mAccessibilityController != null) {
-                    mAccessibilityController.getMagnificationRegionsLocked(
-                            outMagnified, outAvailable);
+                    mAccessibilityController.getMagnificationRegionLocked(magnificationRegion);
                 } else {
                     throw new IllegalStateException("Magnification callbacks not set!");
                 }
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index 5c43659..183a370 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -27,8 +27,10 @@
 #include <utils/misc.h>
 #include <utils/Log.h>
 #include <hardware/hardware.h>
+#include <hardware/power.h>
 #include <suspend/autosuspend.h>
 
+#include <inttypes.h>
 #include <stdio.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -47,6 +49,7 @@
 
 static bool wakeup_init = false;
 static sem_t wakeup_sem;
+extern struct power_module* gPowerModule;
 
 static void wakeup_callback(bool success)
 {
@@ -170,8 +173,122 @@
     return mergedreasonpos - mergedreason;
 }
 
+static jint getPlatformLowPowerStats(JNIEnv* env, jobject /* clazz */, jobject outBuf) {
+    int num_modes = -1;
+    char *output = (char*)env->GetDirectBufferAddress(outBuf), *offset = output;
+    int remaining = (int)env->GetDirectBufferCapacity(outBuf);
+    power_state_platform_sleep_state_t *list;
+    size_t *voter_list;
+    int total_added = -1;
+
+    if (outBuf == NULL) {
+        jniThrowException(env, "java/lang/NullPointerException", "null argument");
+        goto error;
+    }
+
+    if (!gPowerModule) {
+        ALOGE("%s: gPowerModule not loaded", POWER_HARDWARE_MODULE_ID);
+        goto error;
+    }
+
+    if (! (gPowerModule->get_platform_low_power_stats && gPowerModule->get_number_of_platform_modes
+       && gPowerModule->get_voter_list)) {
+        ALOGE("%s: Missing API", POWER_HARDWARE_MODULE_ID);
+        goto error;
+    }
+
+    if (gPowerModule->get_number_of_platform_modes) {
+        num_modes = gPowerModule->get_number_of_platform_modes(gPowerModule);
+    }
+
+    if (num_modes < 1) {
+        ALOGE("%s: Platform does not even have one low power mode", POWER_HARDWARE_MODULE_ID);
+        goto error;
+    }
+
+    list = (power_state_platform_sleep_state_t *)calloc(num_modes,
+        sizeof(power_state_platform_sleep_state_t));
+    if (!list) {
+        ALOGE("%s: power_state_platform_sleep_state_t allocation failed", POWER_HARDWARE_MODULE_ID);
+        goto error;
+    }
+
+    voter_list = (size_t *)calloc(num_modes, sizeof(*voter_list));
+    if (!voter_list) {
+        ALOGE("%s: voter_list allocation failed", POWER_HARDWARE_MODULE_ID);
+        goto err_free;
+    }
+
+    gPowerModule->get_voter_list(gPowerModule, voter_list);
+
+    for (int i = 0; i < num_modes; i++) {
+        list[i].voters = (power_state_voter_t *)calloc(voter_list[i],
+                         sizeof(power_state_voter_t));
+        if (!list[i].voters) {
+            ALOGE("%s: voter_t allocation failed", POWER_HARDWARE_MODULE_ID);
+            goto err_free;
+        }
+    }
+
+    if (!gPowerModule->get_platform_low_power_stats(gPowerModule, list)) {
+        for (int i = 0; i < num_modes; i++) {
+            int added;
+
+            added = snprintf(offset, remaining, "%s_time=%" PRIu64 " %s_count=%" PRIu64 " ",
+                    list[i].name, list[i].residency_in_msec_since_boot, list[i].name,
+                    list[i].total_transitions);
+            if (added < 0) {
+                break;
+            }
+            if (added > remaining) {
+                added = remaining;
+            }
+            offset += added;
+            remaining -= added;
+            total_added += added;
+
+            for (unsigned int j = 0; j < list[i].number_of_voters; j++) {
+                added = snprintf(offset, remaining, "%s_time=%" PRIu64 " %s_count=%" PRIu64 " ",
+                        list[i].voters[j].name,
+                        list[i].voters[j].total_time_in_msec_voted_for_since_boot,
+                        list[i].voters[j].name,
+                        list[i].voters[j].total_number_of_times_voted_since_boot);
+                if (added < 0) {
+                    break;
+                }
+                if (added > remaining) {
+                    added = remaining;
+                }
+                offset += added;
+                remaining -= added;
+                total_added += added;
+            }
+
+            if (remaining <= 0) {
+                /* rewrite NULL character*/
+                offset--;
+                total_added--;
+                ALOGE("%s module: buffer not enough", POWER_HARDWARE_MODULE_ID);
+                break;
+            }
+        }
+    }
+    *offset = 0;
+    total_added += 1;
+
+err_free:
+    for (int i = 0; i < num_modes; i++) {
+        free(list[i].voters);
+    }
+    free(list);
+    free(voter_list);
+error:
+    return total_added;
+}
+
 static const JNINativeMethod method_table[] = {
     { "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
+    { "getPlatformLowPowerStats", "(Ljava/nio/ByteBuffer;)I", (void*)getPlatformLowPowerStats },
 };
 
 int register_android_server_BatteryStatsService(JNIEnv *env)
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 2fdb8e2..cbbfda6a 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -48,7 +48,7 @@
 // ----------------------------------------------------------------------------
 
 static jobject gPowerManagerServiceObj;
-static struct power_module* gPowerModule;
+struct power_module* gPowerModule;
 
 static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];