Merge "AOD: Skip window animations while dozing" into oc-dr1-dev
diff --git a/api/current.txt b/api/current.txt
index d7f8ecd..d5c9945 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -43935,7 +43935,6 @@
     field public static final int KEYBOARD_TAP = 3; // 0x3
     field public static final int LONG_PRESS = 0; // 0x0
     field public static final int VIRTUAL_KEY = 1; // 0x1
-    field public static final int VIRTUAL_KEY_RELEASE = 7; // 0x7
   }
 
   public class InflateException extends java.lang.RuntimeException {
diff --git a/api/system-current.txt b/api/system-current.txt
index 34bba38..8dbff37 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -47474,7 +47474,6 @@
     field public static final int KEYBOARD_TAP = 3; // 0x3
     field public static final int LONG_PRESS = 0; // 0x0
     field public static final int VIRTUAL_KEY = 1; // 0x1
-    field public static final int VIRTUAL_KEY_RELEASE = 7; // 0x7
   }
 
   public class InflateException extends java.lang.RuntimeException {
diff --git a/api/test-current.txt b/api/test-current.txt
index ed9071a..9c1964b 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -44329,7 +44329,6 @@
     field public static final int KEYBOARD_TAP = 3; // 0x3
     field public static final int LONG_PRESS = 0; // 0x0
     field public static final int VIRTUAL_KEY = 1; // 0x1
-    field public static final int VIRTUAL_KEY_RELEASE = 7; // 0x7
   }
 
   public class InflateException extends java.lang.RuntimeException {
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 0d81bd9..7a13ee8 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -488,8 +488,8 @@
      * Instructs the zygote to pre-load the classes and native libraries at the given paths
      * for the specified abi. Not all zygotes support this function.
      */
-    public void preloadPackageForAbi(String packagePath, String libsPath, String cacheKey,
-                                     String abi) throws ZygoteStartFailedEx, IOException {
+    public boolean preloadPackageForAbi(String packagePath, String libsPath, String cacheKey,
+                                        String abi) throws ZygoteStartFailedEx, IOException {
         synchronized(mLock) {
             ZygoteState state = openZygoteSocketIfNeeded(abi);
             state.writer.write("4");
@@ -508,6 +508,8 @@
             state.writer.newLine();
 
             state.writer.flush();
+
+            return (state.inputStream.readInt() == 0);
         }
     }
 
diff --git a/core/java/android/view/HapticFeedbackConstants.java b/core/java/android/view/HapticFeedbackConstants.java
index 0a73949..71a3f7e 100644
--- a/core/java/android/view/HapticFeedbackConstants.java
+++ b/core/java/android/view/HapticFeedbackConstants.java
@@ -58,6 +58,7 @@
 
     /**
      * The user has released a virtual or software keyboard key.
+     * @hide
      */
     public static final int VIRTUAL_KEY_RELEASE = 7;
 
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index ece4981..54afc95 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -69,7 +69,10 @@
 import android.view.animation.Interpolator;
 import android.widget.AbsListView;
 import android.widget.BaseAdapter;
+import android.widget.LinearLayout;
 import android.widget.ListView;
+import android.widget.Space;
+
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity.TargetInfo;
@@ -1412,6 +1415,10 @@
                 } else {
                     lp.height = v.getMeasuredHeight();
                 }
+                if (i != (mColumnCount - 1)) {
+                    row.addView(new Space(ChooserActivity.this),
+                            new LinearLayout.LayoutParams(0, 0, 1));
+                }
             }
 
             // Pre-measure so we can scale later.
@@ -1439,13 +1446,34 @@
             if (startType == ChooserListAdapter.TARGET_SERVICE) {
                 holder.row.setBackgroundColor(
                         getColor(R.color.chooser_service_row_background_color));
+                int nextStartType = mChooserListAdapter.getPositionTargetType(
+                        getFirstRowPosition(rowPosition + 1));
+                int serviceSpacing = holder.row.getContext().getResources()
+                        .getDimensionPixelSize(R.dimen.chooser_service_spacing);
+                int top = rowPosition == 0 ? serviceSpacing : 0;
+                if (nextStartType != ChooserListAdapter.TARGET_SERVICE) {
+                    setVertPadding(holder, top, serviceSpacing);
+                } else {
+                    setVertPadding(holder, top, 0);
+                }
             } else {
                 holder.row.setBackgroundColor(Color.TRANSPARENT);
+                int lastStartType = mChooserListAdapter.getPositionTargetType(
+                        getFirstRowPosition(rowPosition - 1));
+                if (lastStartType == ChooserListAdapter.TARGET_SERVICE || rowPosition == 0) {
+                    int serviceSpacing = holder.row.getContext().getResources()
+                            .getDimensionPixelSize(R.dimen.chooser_service_spacing);
+                    setVertPadding(holder, serviceSpacing, 0);
+                } else {
+                    setVertPadding(holder, 0, 0);
+                }
             }
 
             final int oldHeight = holder.row.getLayoutParams().height;
+            int measuredRowHeight = holder.measuredRowHeight + holder.row.getPaddingTop()
+                    + holder.row.getPaddingBottom();
             holder.row.getLayoutParams().height = Math.max(1,
-                    (int) (holder.measuredRowHeight * getRowScale(rowPosition)));
+                    (int) (measuredRowHeight * getRowScale(rowPosition)));
             if (holder.row.getLayoutParams().height != oldHeight) {
                 holder.row.requestLayout();
             }
@@ -1457,11 +1485,16 @@
                     holder.itemIndices[i] = start + i;
                     mChooserListAdapter.bindView(holder.itemIndices[i], v);
                 } else {
-                    v.setVisibility(View.GONE);
+                    v.setVisibility(View.INVISIBLE);
                 }
             }
         }
 
+        private void setVertPadding(RowViewHolder holder, int top, int bottom) {
+            holder.row.setPadding(holder.row.getPaddingLeft(), top,
+                    holder.row.getPaddingRight(), bottom);
+        }
+
         int getFirstRowPosition(int row) {
             final int callerCount = mChooserListAdapter.getCallerTargetCount();
             final int callerRows = (int) Math.ceil((float) callerCount / mColumnCount);
diff --git a/core/java/com/android/internal/content/FileSystemProvider.java b/core/java/com/android/internal/content/FileSystemProvider.java
index 79544df..ebea1a4 100644
--- a/core/java/com/android/internal/content/FileSystemProvider.java
+++ b/core/java/com/android/internal/content/FileSystemProvider.java
@@ -27,6 +27,7 @@
 import android.database.MatrixCursor.RowBuilder;
 import android.graphics.Point;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.CancellationSignal;
 import android.os.FileObserver;
 import android.os.FileUtils;
@@ -156,11 +157,17 @@
         if (visibleFolder != null) {
             assert (visibleFolder.isDirectory());
 
-            final ContentResolver resolver = getContext().getContentResolver();
-            final Uri uri = MediaStore.Files.getDirectoryUri("external");
-            ContentValues values = new ContentValues();
-            values.put(MediaStore.Files.FileColumns.DATA, visibleFolder.getAbsolutePath());
-            resolver.insert(uri, values);
+            final long token = Binder.clearCallingIdentity();
+
+            try {
+                final ContentResolver resolver = getContext().getContentResolver();
+                final Uri uri = MediaStore.Files.getDirectoryUri("external");
+                ContentValues values = new ContentValues();
+                values.put(MediaStore.Files.FileColumns.DATA, visibleFolder.getAbsolutePath());
+                resolver.insert(uri, values);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
     }
 
@@ -214,22 +221,28 @@
         // They should be all null or not null at the same time. File#renameTo() doesn't work across
         // volumes so an exception will be thrown before calling this method.
         if (oldVisibleFile != null && newVisibleFile != null) {
-            final ContentResolver resolver = getContext().getContentResolver();
-            final Uri externalUri = newVisibleFile.isDirectory()
-                    ? MediaStore.Files.getDirectoryUri("external")
-                    : MediaStore.Files.getContentUri("external");
+            final long token = Binder.clearCallingIdentity();
 
-            ContentValues values = new ContentValues();
-            values.put(MediaStore.Files.FileColumns.DATA, newVisibleFile.getAbsolutePath());
+            try {
+                final ContentResolver resolver = getContext().getContentResolver();
+                final Uri externalUri = newVisibleFile.isDirectory()
+                        ? MediaStore.Files.getDirectoryUri("external")
+                        : MediaStore.Files.getContentUri("external");
 
-            // Logic borrowed from MtpDatabase.
-            // note - we are relying on a special case in MediaProvider.update() to update
-            // the paths for all children in the case where this is a directory.
-            final String path = oldVisibleFile.getAbsolutePath();
-            resolver.update(externalUri,
-                    values,
-                    "_data LIKE ? AND lower(_data)=lower(?)",
-                    new String[] { path, path });
+                ContentValues values = new ContentValues();
+                values.put(MediaStore.Files.FileColumns.DATA, newVisibleFile.getAbsolutePath());
+
+                // Logic borrowed from MtpDatabase.
+                // note - we are relying on a special case in MediaProvider.update() to update
+                // the paths for all children in the case where this is a directory.
+                final String path = oldVisibleFile.getAbsolutePath();
+                resolver.update(externalUri,
+                        values,
+                        "_data LIKE ? AND lower(_data)=lower(?)",
+                        new String[]{path, path});
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
     }
 
@@ -253,23 +266,29 @@
             throws FileNotFoundException {
         // visibleFolder is null if we're removing a document from external thumb drive or SD card.
         if (visibleFile != null) {
-            final ContentResolver resolver = getContext().getContentResolver();
-            final Uri externalUri = MediaStore.Files.getContentUri("external");
+            final long token = Binder.clearCallingIdentity();
 
-            // Remove media store entries for any files inside this directory, using
-            // path prefix match. Logic borrowed from MtpDatabase.
-            if (isFolder) {
-                final String path = visibleFile.getAbsolutePath() + "/";
+            try {
+                final ContentResolver resolver = getContext().getContentResolver();
+                final Uri externalUri = MediaStore.Files.getContentUri("external");
+
+                // Remove media store entries for any files inside this directory, using
+                // path prefix match. Logic borrowed from MtpDatabase.
+                if (isFolder) {
+                    final String path = visibleFile.getAbsolutePath() + "/";
+                    resolver.delete(externalUri,
+                            "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
+                            new String[]{path + "%", Integer.toString(path.length()), path});
+                }
+
+                // Remove media store entry for this exact file.
+                final String path = visibleFile.getAbsolutePath();
                 resolver.delete(externalUri,
-                        "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
-                        new String[] { path + "%", Integer.toString(path.length()), path });
+                        "_data LIKE ?1 AND lower(_data)=lower(?2)",
+                        new String[]{path, path});
+            } finally {
+                Binder.restoreCallingIdentity(token);
             }
-
-            // Remove media store entry for this exact file.
-            final String path = visibleFile.getAbsolutePath();
-            resolver.delete(externalUri,
-                    "_data LIKE ?1 AND lower(_data)=lower(?2)",
-                    new String[] { path, path });
         }
     }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index f3632f0..f085e29 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -840,7 +840,10 @@
             if (sipper.shouldHide) {
                 if (sipper.drainType != BatterySipper.DrainType.OVERCOUNTED
                         && sipper.drainType != BatterySipper.DrainType.SCREEN
-                        && sipper.drainType != BatterySipper.DrainType.UNACCOUNTED) {
+                        && sipper.drainType != BatterySipper.DrainType.UNACCOUNTED
+                        && sipper.drainType != BatterySipper.DrainType.BLUETOOTH
+                        && sipper.drainType != BatterySipper.DrainType.WIFI
+                        && sipper.drainType != BatterySipper.DrainType.IDLE) {
                     // Don't add it if it is overcounted, unaccounted or screen
                     proportionalSmearPowerMah += sipper.totalPowerMah;
                 }
@@ -861,19 +864,19 @@
      * time.
      */
     public void smearScreenBatterySipper(List<BatterySipper> sippers, BatterySipper screenSipper) {
-        final long rawRealtimeMs = SystemClock.elapsedRealtime();
         long totalActivityTimeMs = 0;
         final SparseLongArray activityTimeArray = new SparseLongArray();
         for (int i = 0, size = sippers.size(); i < size; i++) {
             final BatteryStats.Uid uid = sippers.get(i).uidObj;
             if (uid != null) {
-                final long timeMs = getForegroundActivityTotalTimeMs(uid, rawRealtimeMs);
+                final long timeMs = getProcessForegroundTimeMs(uid,
+                        BatteryStats.STATS_SINCE_CHARGED);
                 activityTimeArray.put(uid.getUid(), timeMs);
                 totalActivityTimeMs += timeMs;
             }
         }
 
-        if (totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) {
+        if (screenSipper != null && totalActivityTimeMs >= 10 * DateUtils.MINUTE_IN_MILLIS) {
             final double screenPowerMah = screenSipper.totalPowerMah;
             for (int i = 0, size = sippers.size(); i < size; i++) {
                 final BatterySipper sipper = sippers.get(i);
@@ -936,17 +939,42 @@
         return false;
     }
 
+    public long convertUsToMs(long timeUs) {
+        return timeUs / 1000;
+    }
+
+    public long convertMsToUs(long timeMs) {
+        return timeMs * 1000;
+    }
+
     @VisibleForTesting
-    public long getForegroundActivityTotalTimeMs(BatteryStats.Uid uid, long rawRealtimeMs) {
+    public long getForegroundActivityTotalTimeUs(BatteryStats.Uid uid, long rawRealtimeUs) {
         final BatteryStats.Timer timer = uid.getForegroundActivityTimer();
         if (timer != null) {
-            return timer.getTotalTimeLocked(rawRealtimeMs, BatteryStats.STATS_SINCE_CHARGED);
+            return timer.getTotalTimeLocked(rawRealtimeUs, BatteryStats.STATS_SINCE_CHARGED);
         }
 
         return 0;
     }
 
     @VisibleForTesting
+    public long getProcessForegroundTimeMs(BatteryStats.Uid uid, int which) {
+        final long rawRealTimeUs = convertMsToUs(SystemClock.elapsedRealtime());
+        final int foregroundTypes[] = {BatteryStats.Uid.PROCESS_STATE_TOP};
+
+        long timeUs = 0;
+        for (int type : foregroundTypes) {
+            final long localTime = uid.getProcessStateTime(type, rawRealTimeUs, which);
+            timeUs += localTime;
+        }
+
+        // Return the min value of STATE_TOP time and foreground activity time, since both of these
+        // time have some errors.
+        return convertUsToMs(
+                Math.min(timeUs, getForegroundActivityTotalTimeUs(uid, rawRealTimeUs)));
+    }
+
+    @VisibleForTesting
     public void setPackageManager(PackageManager packageManager) {
         mPackageManager = packageManager;
     }
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index e28079f..58e4a3e 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -26,6 +26,7 @@
 import android.webkit.WebViewFactory;
 import android.webkit.WebViewFactoryProvider;
 
+import java.io.DataOutputStream;
 import java.io.File;
 import java.io.IOException;
 import java.lang.reflect.InvocationTargetException;
@@ -87,17 +88,28 @@
             // Once we have the classloader, look up the WebViewFactoryProvider implementation and
             // call preloadInZygote() on it to give it the opportunity to preload the native library
             // and perform any other initialisation work that should be shared among the children.
+            boolean preloadSucceeded = false;
             try {
                 Class<WebViewFactoryProvider> providerClass =
                         WebViewFactory.getWebViewProviderClass(loader);
                 Object result = providerClass.getMethod("preloadInZygote").invoke(null);
-                if (!((Boolean)result).booleanValue()) {
+                preloadSucceeded = ((Boolean) result).booleanValue();
+                if (!preloadSucceeded) {
                     Log.e(TAG, "preloadInZygote returned false");
                 }
             } catch (ClassNotFoundException | NoSuchMethodException | SecurityException |
                      IllegalAccessException | InvocationTargetException e) {
                 Log.e(TAG, "Exception while preloading package", e);
             }
+
+            try {
+                DataOutputStream socketOut = getSocketOutputStream();
+                socketOut.writeInt(preloadSucceeded ? 1 : 0);
+            } catch (IOException ioe) {
+                Log.e(TAG, "Error writing to command socket", ioe);
+                return true;
+            }
+
             Log.i(TAG, "Package preload done");
             return false;
         }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 2013ac0..f0c0b99 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -314,6 +314,10 @@
         return ZygoteInit.isPreloadComplete();
     }
 
+    protected DataOutputStream getSocketOutputStream() {
+        return mSocketOutStream;
+    }
+
     protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) {
         throw new RuntimeException("Zyogte does not support package preloading");
     }
diff --git a/core/res/res/layout/chooser_row.xml b/core/res/res/layout/chooser_row.xml
index 9baa32c..6c1271d 100644
--- a/core/res/res/layout/chooser_row.xml
+++ b/core/res/res/layout/chooser_row.xml
@@ -18,11 +18,9 @@
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:orientation="horizontal"
-              android:layout_width="match_parent" android:layout_height="wrap_content"
-              android:minHeight="80dp"
+              android:layout_width="match_parent"
+              android:layout_height="100dp"
               android:gravity="start|top"
-              android:paddingTop="8dp"
-              android:paddingBottom="8dp"
               android:paddingStart="@dimen/chooser_grid_padding"
               android:paddingEnd="@dimen/chooser_grid_padding"
               android:weightSum="4">
diff --git a/core/res/res/layout/resolve_grid_item.xml b/core/res/res/layout/resolve_grid_item.xml
index 305c8b0..71c153f 100644
--- a/core/res/res/layout/resolve_grid_item.xml
+++ b/core/res/res/layout/resolve_grid_item.xml
@@ -18,10 +18,9 @@
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               android:orientation="vertical"
-              android:layout_width="0dp"
+              android:layout_width="76dp"
               android:layout_height="wrap_content"
-              android:layout_weight="1"
-              android:minWidth="80dp"
+              android:minHeight="100dp"
               android:gravity="center"
               android:paddingTop="8dp"
               android:paddingBottom="8dp"
@@ -49,7 +48,7 @@
     <TextView android:id="@android:id/text1"
               android:layout_width="wrap_content"
               android:layout_height="wrap_content"
-              android:layout_marginTop="8dp"
+              android:layout_marginTop="4dp"
               android:layout_marginLeft="4dp"
               android:layout_marginRight="4dp"
               android:textAppearance="?attr/textAppearanceSmall"
diff --git a/core/res/res/layout/shutdown_dialog.xml b/core/res/res/layout/shutdown_dialog.xml
new file mode 100644
index 0000000..398bfb1
--- /dev/null
+++ b/core/res/res/layout/shutdown_dialog.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+     Copyright (C) 2014 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical"
+    android:gravity="center_horizontal" >
+
+    <Space
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="6" />
+
+    <TextView
+        android:id="@id/text1"
+        android:layout_width="wrap_content"
+        android:layout_height="32dp"
+        android:text="@string/shutdown_progress"
+        android:textDirection="locale"
+        android:textSize="24sp"
+        android:textAppearance="?attr/textAppearanceLarge"
+        android:gravity="center"
+        android:layout_marginBottom="24dp"
+        android:fontFamily="@string/config_headlineFontFamily"/>
+
+    <ProgressBar
+        android:id="@id/progress"
+        android:layout_width="30dp"
+        android:layout_height="30dp"
+        style="?attr/progressBarStyleLarge" />
+
+    <Space
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="10" />
+
+</LinearLayout>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 69bb0b9..ab909cf 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -284,6 +284,13 @@
          Settings.Global.NETWORK_AVOID_BAD_WIFI. This is the default value of that setting. -->
     <integer translatable="false" name="config_networkAvoidBadWifi">1</integer>
 
+    <!-- If the hardware supports specially marking packets that caused a wakeup of the
+         main CPU, set this value to the mark used. -->
+    <integer name="config_networkWakeupPacketMark">0</integer>
+
+    <!-- Mask to use when checking skb mark defined in config_networkWakeupPacketMark above. -->
+    <integer name="config_networkWakeupPacketMask">0</integer>
+
     <!-- Default value for ConnectivityManager.getMultipathPreference() on metered networks. Actual
          device behaviour is controlled by Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE.
          This is the default value of that setting. -->
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index fa33d56..9f9c883 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -533,6 +533,8 @@
     <dimen name="content_rect_bottom_clip_allowance">20dp</dimen>
 
     <dimen name="chooser_grid_padding">0dp</dimen>
+    <!-- Spacing around the background change frome service to non-service -->
+    <dimen name="chooser_service_spacing">8dp</dimen>
 
     <item type="dimen" name="aerr_padding_list_top">15dp</item>
     <item type="dimen" name="aerr_padding_list_bottom">8dp</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 99807f9..ad9b5af 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1838,6 +1838,8 @@
   <java-symbol type="integer" name="config_networkNotifySwitchType" />
   <java-symbol type="array" name="config_networkNotifySwitches" />
   <java-symbol type="integer" name="config_networkAvoidBadWifi" />
+  <java-symbol type="integer" name="config_networkWakeupPacketMark" />
+  <java-symbol type="integer" name="config_networkWakeupPacketMask" />
   <java-symbol type="integer" name="config_networkMeteredMultipathPreference" />
   <java-symbol type="integer" name="config_notificationsBatteryFullARGB" />
   <java-symbol type="integer" name="config_notificationsBatteryLedOff" />
@@ -3058,4 +3060,6 @@
   <java-symbol type="array" name="config_batteryPackageTypeSystem" />
   <java-symbol type="array" name="config_batteryPackageTypeService" />
   <java-symbol type="bool" name="config_showAreaUpdateInfoSettings" />
+  <java-symbol type="layout" name="shutdown_dialog" />
+  <java-symbol type="dimen" name="chooser_service_spacing" />
 </resources>
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
index f01c33f..e81f678 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsHelperTest.java
@@ -18,9 +18,12 @@
 package com.android.internal.os;
 
 
+import static android.os.BatteryStats.Uid.PROCESS_STATE_TOP;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.RETURNS_DEEP_STUBS;
@@ -54,11 +57,16 @@
 @SmallTest
 public class BatteryStatsHelperTest extends TestCase {
     private static final long TIME_FOREGROUND_ACTIVITY_ZERO = 0;
-    private static final long TIME_FOREGROUND_ACTIVITY = 100 * DateUtils.MINUTE_IN_MILLIS;
+    private static final long TIME_FOREGROUND_ACTIVITY = 100 * DateUtils.MINUTE_IN_MILLIS * 1000;
+    private static final long TIME_STATE_FOREGROUND_MS = 10 * DateUtils.MINUTE_IN_MILLIS;
+    private static final long TIME_STATE_FOREGROUND_US = TIME_STATE_FOREGROUND_MS * 1000;
 
     private static final int UID = 123456;
     private static final double BATTERY_SCREEN_USAGE = 300;
     private static final double BATTERY_SYSTEM_USAGE = 600;
+    private static final double BATTERY_WIFI_USAGE = 200;
+    private static final double BATTERY_IDLE_USAGE = 600;
+    private static final double BATTERY_BLUETOOTH_USAGE = 300;
     private static final double BATTERY_OVERACCOUNTED_USAGE = 500;
     private static final double BATTERY_UNACCOUNTED_USAGE = 700;
     private static final double BATTERY_APP_USAGE = 100;
@@ -68,6 +76,12 @@
     @Mock
     private BatteryStats.Uid mUid;
     @Mock
+    private BatterySipper mWifiBatterySipper;
+    @Mock
+    private BatterySipper mBluetoothBatterySipper;
+    @Mock
+    private BatterySipper mIdleBatterySipper;
+    @Mock
     private BatterySipper mNormalBatterySipper;
     @Mock
     private BatterySipper mScreenBatterySipper;
@@ -109,6 +123,15 @@
         mUnaccountedBatterySipper.drainType = BatterySipper.DrainType.UNACCOUNTED;
         mUnaccountedBatterySipper.totalPowerMah = BATTERY_UNACCOUNTED_USAGE;
 
+        mWifiBatterySipper.drainType = BatterySipper.DrainType.WIFI;
+        mWifiBatterySipper.totalPowerMah = BATTERY_WIFI_USAGE;
+
+        mBluetoothBatterySipper.drainType = BatterySipper.DrainType.BLUETOOTH;
+        mBluetoothBatterySipper.totalPowerMah = BATTERY_BLUETOOTH_USAGE;
+
+        mIdleBatterySipper.drainType = BatterySipper.DrainType.IDLE;
+        mIdleBatterySipper.totalPowerMah = BATTERY_IDLE_USAGE;
+
         mContext = InstrumentationRegistry.getContext();
         mBatteryStatsHelper = spy(new BatteryStatsHelper(mContext));
         mBatteryStatsHelper.setPackageManager(mPackageManager);
@@ -165,6 +188,9 @@
         sippers.add(mSystemBatterySipper);
         sippers.add(mOvercountedBatterySipper);
         sippers.add(mUnaccountedBatterySipper);
+        sippers.add(mWifiBatterySipper);
+        sippers.add(mBluetoothBatterySipper);
+        sippers.add(mIdleBatterySipper);
         doReturn(true).when(mBatteryStatsHelper).isTypeSystem(mSystemBatterySipper);
         doNothing().when(mBatteryStatsHelper).smearScreenBatterySipper(any(), any());
 
@@ -219,6 +245,19 @@
         assertThat(mBatteryStatsHelper.isTypeService(mNormalBatterySipper)).isTrue();
     }
 
+    @Test
+    public void testGetProcessForegroundTimeMs_largerActivityTime_returnMinTime() {
+        doReturn(TIME_STATE_FOREGROUND_US + 500).when(mBatteryStatsHelper)
+                .getForegroundActivityTotalTimeUs(eq(mUid), anyLong());
+        doReturn(TIME_STATE_FOREGROUND_US).when(mUid).getProcessStateTime(eq(PROCESS_STATE_TOP),
+                anyLong(), anyInt());
+
+        final long time = mBatteryStatsHelper.getProcessForegroundTimeMs(mUid,
+                BatteryStats.STATS_SINCE_CHARGED);
+
+        assertThat(time).isEqualTo(TIME_STATE_FOREGROUND_MS);
+    }
+
     private BatterySipper createTestSmearBatterySipper(long activityTime, double totalPowerMah,
             int uidCode, boolean isUidNull) {
         final BatterySipper sipper = mock(BatterySipper.class);
@@ -227,8 +266,8 @@
         doReturn(uidCode).when(sipper).getUid();
         if (!isUidNull) {
             final BatteryStats.Uid uid = mock(BatteryStats.Uid.class, RETURNS_DEEP_STUBS);
-            doReturn(activityTime).when(mBatteryStatsHelper).getForegroundActivityTotalTimeMs(
-                    eq(uid), anyLong());
+            doReturn(activityTime).when(mBatteryStatsHelper).getProcessForegroundTimeMs(eq(uid),
+                    anyInt());
             doReturn(uidCode).when(uid).getUid();
             sipper.uidObj = uid;
         }
@@ -236,5 +275,4 @@
         return sipper;
     }
 
-
 }
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index a430288..064cc84 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -465,6 +465,8 @@
     <string name="wifi_allow_scan_with_traffic">Always allow Wi\u2011Fi Roam Scans</string>
     <!-- Setting Checkbox title whether to always keep mobile data active. [CHAR LIMIT=80] -->
     <string name="mobile_data_always_on">Mobile data always active</string>
+    <!-- Setting Checkbox title whether to enable hardware acceleration for tethering. [CHAR LIMIT=80] -->
+    <string name="tethering_hardware_offload">Tethering hardware acceleration</string>
     <!-- Setting Checkbox title for disabling Bluetooth absolute volume -->
     <string name="bluetooth_disable_absolute_volume">Disable absolute volume</string>
     <!-- Setting Checkbox title for enabling Bluetooth inband ringing -->
@@ -534,6 +536,7 @@
     <!-- Setting Checkbox title whether to enable view attribute inspection -->
     <string name="debug_view_attributes">Enable view attribute inspection</string>
     <string name="mobile_data_always_on_summary">Always keep mobile data active, even when Wi\u2011Fi is active (for fast network switching).</string>
+    <string name="tethering_hardware_offload_summary">Use tethering hardware acceleration if available</string>
     <!-- Title of warning dialog about the implications of enabling USB debugging -->
     <string name="adb_warning_title">Allow USB debugging?</string>
     <!-- Warning text to user about the implications of enabling USB debugging -->
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 5767823..dee5a93 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -130,7 +130,7 @@
     }
 
     /** Formats a double from 0.0..1.0 as a percentage. */
-    private static String formatPercentage(double percentage) {
+    public static String formatPercentage(double percentage) {
         return NumberFormat.getPercentInstance().format(percentage);
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
index e4e0f7f..c4cbc2b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/InterestingConfigChanges.java
@@ -36,7 +36,8 @@
     }
 
     public boolean applyNewConfig(Resources res) {
-        int configChanges = mLastConfiguration.updateFrom(res.getConfiguration());
+        int configChanges = mLastConfiguration.updateFrom(
+                Configuration.generateDelta(mLastConfiguration, res.getConfiguration()));
         boolean densityChanged = mLastDensity != res.getDisplayMetrics().densityDpi;
         if (densityChanged || (configChanges & (mFlags)) != 0) {
             mLastDensity = res.getDisplayMetrics().densityDpi;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
index 80b943c..d07da93 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothEventManager.java
@@ -102,6 +102,7 @@
         // Fine-grained state broadcasts
         addHandler(BluetoothDevice.ACTION_CLASS_CHANGED, new ClassChangedHandler());
         addHandler(BluetoothDevice.ACTION_UUID, new UuidChangedHandler());
+        addHandler(BluetoothDevice.ACTION_BATTERY_LEVEL_CHANGED, new BatteryLevelChangedHandler());
 
         // Dock event broadcasts
         addHandler(Intent.ACTION_DOCK_EVENT, new DockEventHandler());
@@ -376,6 +377,17 @@
             }
         }
     }
+
+    private class BatteryLevelChangedHandler implements Handler {
+        public void onReceive(Context context, Intent intent,
+                BluetoothDevice device) {
+            CachedBluetoothDevice cachedDevice = mDeviceManager.findDevice(device);
+            if (cachedDevice != null) {
+                cachedDevice.refresh();
+            }
+        }
+    }
+
     boolean readPairedDevices() {
         Set<BluetoothDevice> bondedDevices = mLocalAdapter.getBondedDevices();
         if (bondedDevices == null) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index e279a09..4bb4b40 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -368,6 +368,15 @@
         return mDevice;
     }
 
+    /**
+     * Convenience method that can be mocked - it lets tests avoid having to call getDevice() which
+     * causes problems in tests since BluetoothDevice is final and cannot be mocked.
+     * @return the address of this device
+     */
+    public String getAddress() {
+        return mDevice.getAddress();
+    }
+
     public String getName() {
         return mName;
     }
@@ -410,6 +419,14 @@
         }
     }
 
+    /**
+     * Get battery level from remote device
+     * @return battery level in percentage [0-100], or {@link BluetoothDevice#BATTERY_LEVEL_UNKNOWN}
+     */
+    public int getBatteryLevel() {
+        return mDevice.getBatteryLevel();
+    }
+
     void refresh() {
         dispatchAttributesChanged();
     }
@@ -828,7 +845,7 @@
     /**
      * @return resource for string that discribes the connection state of this device.
      */
-    public int getConnectionSummary() {
+    public String getConnectionSummary() {
         boolean profileConnected = false;       // at least one profile is connected
         boolean a2dpNotConnected = false;       // A2DP is preferred but not connected
         boolean hfpNotConnected = false;    // HFP is preferred but not connected
@@ -839,7 +856,7 @@
             switch (connectionStatus) {
                 case BluetoothProfile.STATE_CONNECTING:
                 case BluetoothProfile.STATE_DISCONNECTING:
-                    return Utils.getConnectionStateSummary(connectionStatus);
+                    return mContext.getString(Utils.getConnectionStateSummary(connectionStatus));
 
                 case BluetoothProfile.STATE_CONNECTED:
                     profileConnected = true;
@@ -859,18 +876,54 @@
             }
         }
 
+        String batteryLevelPercentageString = null;
+        // Android framework should only set mBatteryLevel to valid range [0-100] or
+        // BluetoothDevice.BATTERY_LEVEL_UNKNOWN, any other value should be a framework bug.
+        // Thus assume here that if value is not BluetoothDevice.BATTERY_LEVEL_UNKNOWN, it must
+        // be valid
+        final int batteryLevel = getBatteryLevel();
+        if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+            // TODO: name com.android.settingslib.bluetooth.Utils something different
+            batteryLevelPercentageString =
+                    com.android.settingslib.Utils.formatPercentage(batteryLevel);
+        }
+
         if (profileConnected) {
             if (a2dpNotConnected && hfpNotConnected) {
-                return R.string.bluetooth_connected_no_headset_no_a2dp;
+                if (batteryLevelPercentageString != null) {
+                    return mContext.getString(
+                            R.string.bluetooth_connected_no_headset_no_a2dp_battery_level,
+                            batteryLevelPercentageString);
+                } else {
+                    return mContext.getString(R.string.bluetooth_connected_no_headset_no_a2dp);
+                }
+
             } else if (a2dpNotConnected) {
-                return R.string.bluetooth_connected_no_a2dp;
+                if (batteryLevelPercentageString != null) {
+                    return mContext.getString(R.string.bluetooth_connected_no_a2dp_battery_level,
+                            batteryLevelPercentageString);
+                } else {
+                    return mContext.getString(R.string.bluetooth_connected_no_a2dp);
+                }
+
             } else if (hfpNotConnected) {
-                return R.string.bluetooth_connected_no_headset;
+                if (batteryLevelPercentageString != null) {
+                    return mContext.getString(R.string.bluetooth_connected_no_headset_battery_level,
+                            batteryLevelPercentageString);
+                } else {
+                    return mContext.getString(R.string.bluetooth_connected_no_headset);
+                }
             } else {
-                return R.string.bluetooth_connected;
+                if (batteryLevelPercentageString != null) {
+                    return mContext.getString(R.string.bluetooth_connected_battery_level,
+                            batteryLevelPercentageString);
+                } else {
+                    return mContext.getString(R.string.bluetooth_connected);
+                }
             }
         }
 
-        return getBondState() == BluetoothDevice.BOND_BONDING ? R.string.bluetooth_pairing : 0;
+        return getBondState() == BluetoothDevice.BOND_BONDING ?
+                mContext.getString(R.string.bluetooth_pairing) : null;
     }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
index 5529866..d45fe1a 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HeadsetProfile.java
@@ -34,7 +34,7 @@
 /**
  * HeadsetProfile handles Bluetooth HFP and Headset profiles.
  */
-public final class HeadsetProfile implements LocalBluetoothProfile {
+public class HeadsetProfile implements LocalBluetoothProfile {
     private static final String TAG = "HeadsetProfile";
     private static boolean V = true;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
index a9e8db5..d1621da 100755
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/HidProfile.java
@@ -31,7 +31,7 @@
 /**
  * HidProfile handles Bluetooth HID profile.
  */
-public final class HidProfile implements LocalBluetoothProfile {
+public class HidProfile implements LocalBluetoothProfile {
     private static final String TAG = "HidProfile";
     private static boolean V = true;
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 4a54451..ec41415 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -1053,7 +1053,8 @@
     }
 
     /** Attempt to update the AccessPoint and return true if an update occurred. */
-    public boolean update(WifiConfiguration config, WifiInfo info, NetworkInfo networkInfo) {
+    public boolean update(
+            @Nullable WifiConfiguration config, WifiInfo info, NetworkInfo networkInfo) {
         boolean updated = false;
         final int oldLevel = getLevel();
         if (info != null && isInfoForThisAccessPoint(config, info)) {
@@ -1088,9 +1089,9 @@
         return updated;
     }
 
-    void update(WifiConfiguration config) {
+    void update(@Nullable WifiConfiguration config) {
         mConfig = config;
-        networkId = config.networkId;
+        networkId = config != null ? config.networkId : WifiConfiguration.INVALID_NETWORK_ID;
         if (mAccessPointListener != null) {
             mAccessPointListener.onAccessPointChanged(this);
         }
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
index 5c64cff..c08dd6e 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/AccessPointTest.java
@@ -656,4 +656,28 @@
         assertThat(ap.update(newConfig, wifiInfo, networkInfo)).isFalse();
         verify(mockListener).onAccessPointChanged(ap);
     }
+
+    @Test
+    public void testUpdateWithNullWifiConfiguration_doesNotThrowNPE() {
+        int networkId = 123;
+        int rssi = -55;
+        WifiConfiguration config = new WifiConfiguration();
+        config.networkId = networkId;
+        WifiInfo wifiInfo = new WifiInfo();
+        wifiInfo.setNetworkId(networkId);
+        wifiInfo.setRssi(rssi);
+
+        NetworkInfo networkInfo =
+                new NetworkInfo(ConnectivityManager.TYPE_WIFI, 0 /* subtype */, "WIFI", "");
+        networkInfo.setDetailedState(NetworkInfo.DetailedState.CONNECTING, "", "");
+
+        AccessPoint ap = new TestAccessPointBuilder(mContext)
+                .setNetworkInfo(networkInfo)
+                .setNetworkId(networkId)
+                .setRssi(rssi)
+                .setWifiInfo(wifiInfo)
+                .build();
+
+        ap.update(null, wifiInfo, networkInfo);
+    }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
new file mode 100644
index 0000000..e2ebbeb
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.settingslib.bluetooth;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothProfile;
+import android.content.Context;
+
+import com.android.settingslib.R;
+import com.android.settingslib.TestConfig;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+@RunWith(RobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION, resourceDir =
+        "../../res")
+public class CachedBluetoothDeviceTest {
+    @Mock
+    private LocalBluetoothAdapter mAdapter;
+    @Mock
+    private LocalBluetoothProfileManager mProfileManager;
+    @Mock
+    private HeadsetProfile mHfpProfile;
+    @Mock
+    private A2dpProfile mA2dpProfile;
+    @Mock
+    private HidProfile mHidProfile;
+    @Mock
+    private BluetoothDevice mDevice;
+    private CachedBluetoothDevice mCachedDevice;
+    private Context mContext;
+    private int mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+        when(mAdapter.getBluetoothState()).thenReturn(BluetoothAdapter.STATE_ON);
+        when(mHfpProfile.isProfileReady()).thenReturn(true);
+        when(mA2dpProfile.isProfileReady()).thenReturn(true);
+        when(mHidProfile.isProfileReady()).thenReturn(true);
+        mCachedDevice = spy(
+                new CachedBluetoothDevice(mContext, mAdapter, mProfileManager, mDevice));
+        doAnswer((invocation) -> mBatteryLevel).when(mCachedDevice).getBatteryLevel();
+    }
+
+    /**
+     * Test to verify the current test context object works so that we are not checking null
+     * against null
+     */
+    @Test
+    public void testContextMock() {
+        assertThat(mContext.getString(R.string.bluetooth_connected)).isEqualTo("Connected");
+    }
+
+    @Test
+    public void testGetConnectionSummary_testSingleProfileConnectDisconnect() {
+        // Test without battery level
+        // Set HID profile to be connected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
+                R.string.bluetooth_connected));
+
+        // Set HID profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+
+        // Test with battery level
+        mBatteryLevel = 10;
+        // Set HID profile to be connected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
+                R.string.bluetooth_connected_battery_level,
+                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+
+        // Set HID profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+
+        // Test with BluetoothDevice.BATTERY_LEVEL_UNKNOWN battery level
+        mBatteryLevel = BluetoothDevice.BATTERY_LEVEL_UNKNOWN;
+
+        // Set HID profile to be connected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
+                R.string.bluetooth_connected));
+
+        // Set HID profile to be disconnected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+    }
+
+    @Test
+    public void testGetConnectionSummary_testMultipleProfileConnectDisconnect() {
+        mBatteryLevel = 10;
+
+        // Set HFP, A2DP and HID profile to be connected and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_CONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
+                R.string.bluetooth_connected_battery_level,
+                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+
+        // Disconnect HFP only and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
+                R.string.bluetooth_connected_no_headset_battery_level,
+                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+
+        // Disconnect A2DP only and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_CONNECTED);
+        mCachedDevice.onProfileStateChanged(mA2dpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
+                R.string.bluetooth_connected_no_a2dp_battery_level,
+                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+
+        // Disconnect both HFP and A2DP and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHfpProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isEqualTo(mContext.getString(
+                R.string.bluetooth_connected_no_headset_no_a2dp_battery_level,
+                com.android.settingslib.Utils.formatPercentage(mBatteryLevel)));
+
+        // Disconnect all profiles and test connection state summary
+        mCachedDevice.onProfileStateChanged(mHidProfile, BluetoothProfile.STATE_DISCONNECTED);
+        assertThat(mCachedDevice.getConnectionSummary()).isNull();
+    }
+}
diff --git a/packages/SystemUI/res/drawable/brightness_mirror_background.xml b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
index 0c69d89..b3a0484 100644
--- a/packages/SystemUI/res/drawable/brightness_mirror_background.xml
+++ b/packages/SystemUI/res/drawable/brightness_mirror_background.xml
@@ -15,5 +15,5 @@
   ~ limitations under the License
   -->
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="?android:attr/colorPrimary" />
+    <solid android:color="@color/qs_background_dark" />
 </shape>
diff --git a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
index 2ff626a..f8b7b8a 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_expanded_header.xml
@@ -33,13 +33,13 @@
 
     <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="32dp"
+        android:layout_height="40dp"
         android:layout_alignParentEnd="true"
         android:clipChildren="false"
         android:clipToPadding="false"
         android:gravity="center"
-        android:paddingStart="16dp"
-        android:paddingEnd="16dp"
+        android:paddingStart="8dp"
+        android:paddingEnd="8dp"
         android:orientation="horizontal">
 
 
diff --git a/packages/SystemUI/res/layout/recents_empty.xml b/packages/SystemUI/res/layout/recents_empty.xml
index 53d9cc5..8048c68 100644
--- a/packages/SystemUI/res/layout/recents_empty.xml
+++ b/packages/SystemUI/res/layout/recents_empty.xml
@@ -23,7 +23,8 @@
     android:drawableTop="@drawable/recents_empty"
     android:drawablePadding="25dp"
     android:textSize="16sp"
-    android:textColor="#ffffffff"
+    android:drawableTint="?attr/bgProtectTextColor"
+    android:textColor="?attr/bgProtectTextColor"
     android:text="@string/recents_empty_message"
     android:fontFamily="sans-serif"
     android:visibility="gone" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/recents_stack_action_button.xml b/packages/SystemUI/res/layout/recents_stack_action_button.xml
index 34b4e17..10b4316 100644
--- a/packages/SystemUI/res/layout/recents_stack_action_button.xml
+++ b/packages/SystemUI/res/layout/recents_stack_action_button.xml
@@ -24,7 +24,7 @@
     android:paddingBottom="12dp"
     android:text="@string/recents_stack_action_button_label"
     android:textSize="14sp"
-    android:textColor="#FFFFFF"
+    android:textColor="?attr/bgProtectTextColor"
     android:textAllCaps="true"
     android:shadowColor="#99000000"
     android:shadowDx="0"
diff --git a/packages/SystemUI/res/layout/rounded_corners.xml b/packages/SystemUI/res/layout/rounded_corners.xml
index 8d391e0..d1ef5d6 100644
--- a/packages/SystemUI/res/layout/rounded_corners.xml
+++ b/packages/SystemUI/res/layout/rounded_corners.xml
@@ -22,6 +22,7 @@
         android:id="@+id/left"
         android:layout_width="12dp"
         android:layout_height="12dp"
+        android:layout_gravity="left"
         android:tint="#ff000000"
         android:src="@drawable/rounded" />
     <ImageView
@@ -29,6 +30,6 @@
         android:layout_width="12dp"
         android:layout_height="12dp"
         android:tint="#ff000000"
-        android:layout_gravity="end"
+        android:layout_gravity="right"
         android:src="@drawable/rounded" />
 </FrameLayout>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 5274b64..93a0742 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <style name="RecentsTheme" parent="@android:style/Theme.Material">
+    <style name="RecentsTheme" parent="RecentsBase">
         <!-- NoTitle -->
         <item name="android:windowNoTitle">true</item>
         <!-- Misc -->
@@ -27,6 +27,12 @@
         <item name="android:ambientShadowAlpha">0.35</item>
     </style>
 
+    <!-- OverlayManager might replace this style entirely, use RecentsTheme to set a property
+    that should exist in both light and dark versions of Recents -->
+    <style name="RecentsBase" parent="@android:style/Theme.Material">
+        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_dark</item>
+        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_dark</item>
+    </style>
 
     <!-- Recents theme -->
     <style name="RecentsTheme.Wallpaper">
@@ -35,6 +41,8 @@
         <item name="android:windowShowWallpaper">true</item>
         <item name="android:windowDisablePreview">true</item>
         <item name="clearAllStyle">@style/ClearAllButtonDefaultMargins</item>
+        <item name="bgProtectTextColor">?android:attr/textColorPrimaryInverse</item>
+        <item name="bgProtectSecondaryTextColor">?android:attr/textColorSecondaryInverse</item>
     </style>
 
     <style name="ClearAllButtonDefaultMargins">
@@ -47,6 +55,8 @@
     <!-- Performance optimized Recents theme (no wallpaper) -->
     <style name="RecentsTheme.NoWallpaper">
         <item name="android:windowBackground">@android:color/black</item>
+        <item name="bgProtectTextColor">@android:color/white</item>
+        <item name="bgProtectSecondaryTextColor">@android:color/white</item>
     </style>
 
     <!-- Theme used for the activity that shows when the system forced an app to be resizable -->
@@ -290,7 +300,10 @@
     <style name="Animation.StatusBar">
     </style>
 
-    <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
+    <!-- Overlay manager may replace this theme -->
+    <style name="systemui_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings" />
+
+    <style name="systemui_theme" parent="systemui_base">
         <item name="lightIconTheme">@style/DualToneLightTheme</item>
         <item name="darkIconTheme">@style/DualToneDarkTheme</item>
         <item name="bgProtectTextColor">?android:attr/textColorPrimaryInverse</item>
@@ -303,7 +316,10 @@
         <item name="*android:successColor">?android:attr/textColorPrimaryInverse</item>
     </style>
 
-    <style name="qs_theme" parent="systemui_theme">
+    <!-- Overlay manager may replace this theme -->
+    <style name="qs_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings" />
+
+    <style name="qs_theme" parent="qs_base">
         <item name="lightIconTheme">@style/QSIconTheme</item>
         <item name="darkIconTheme">@style/QSIconTheme</item>
     </style>
@@ -459,7 +475,7 @@
         <item name="android:paddingEnd">8dp</item>
     </style>
 
-    <style name="edit_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
+    <style name="edit_theme" parent="qs_base">
         <item name="android:colorBackground">?android:attr/colorSecondary</item>
     </style>
 
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index 7fed3e8..377fab5 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -545,6 +545,16 @@
      */
     @VisibleForTesting
     void finishExpanding(boolean forceAbort, float velocity) {
+        finishExpanding(forceAbort, velocity, true /* allowAnimation */);
+    }
+
+    /**
+     * Finish the current expand motion
+     * @param forceAbort whether the expansion should be forcefully aborted and returned to the old
+     *                   state
+     * @param velocity the velocity this was expanded/ collapsed with
+     */
+    private void finishExpanding(boolean forceAbort, float velocity, boolean allowAnimation) {
         if (!mExpanding) return;
 
         if (DEBUG) Log.d(TAG, "scale in finishing on view: " + mResizedView);
@@ -568,7 +578,7 @@
         mCallback.expansionStateChanged(false);
         int naturalHeight = mScaler.getNaturalHeight();
         float targetHeight = nowExpanded ? naturalHeight : mSmallSize;
-        if (targetHeight != currentHeight && mEnabled) {
+        if (targetHeight != currentHeight && mEnabled && allowAnimation) {
             mScaleAnimation.setFloatValues(targetHeight);
             mScaleAnimation.setupStartValues();
             final View scaledView = mResizedView;
@@ -622,10 +632,22 @@
     }
 
     /**
+     * Use this to abort any pending expansions in progress and force that there will be no
+     * animations.
+     */
+    public void cancelImmediately() {
+        cancel(false /* allowAnimation */);
+    }
+
+    /**
      * Use this to abort any pending expansions in progress.
      */
     public void cancel() {
-        finishExpanding(true /* forceAbort */, 0f /* velocity */);
+        cancel(true /* allowAnimation */);
+    }
+
+    private void cancel(boolean allowAnimation) {
+        finishExpanding(true /* forceAbort */, 0f /* velocity */, allowAnimation);
         clearView();
 
         // reset the gesture detector
diff --git a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
index bb0f2f9..22bb2a3 100644
--- a/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/HardwareUiLayout.java
@@ -19,6 +19,7 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.view.Gravity;
@@ -28,9 +29,15 @@
 import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
-
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.leak.RotationUtils;
+
+import java.util.ArrayList;
+
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_NONE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
 
 public class HardwareUiLayout extends FrameLayout implements Tunable {
 
@@ -49,7 +56,7 @@
     private int mEndPoint;
     private boolean mEdgeBleed;
     private boolean mRoundedDivider;
-    private boolean mLandscape;
+    private int mRotation = ROTATION_NONE;
     private boolean mRotatedBackground;
 
     public HardwareUiLayout(Context context, AttributeSet attrs) {
@@ -93,8 +100,10 @@
     private void updateEdgeMargin(int edge) {
         if (mChild != null) {
             MarginLayoutParams params = (MarginLayoutParams) mChild.getLayoutParams();
-            if (mLandscape) {
+            if (mRotation == ROTATION_LANDSCAPE) {
                 params.topMargin = edge;
+            } else if (mRotation == ROTATION_SEASCAPE) {
+                params.bottomMargin = edge;
             } else {
                 params.rightMargin = edge;
             }
@@ -118,6 +127,7 @@
                 mChild.addOnLayoutChangeListener(
                         (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
                                 updatePosition());
+                updateRotation();
             } else {
                 return;
             }
@@ -127,30 +137,69 @@
             animateChild(mOldHeight, newHeight);
         }
         post(() -> updatePosition());
-        boolean landscape = getMeasuredWidth() > getMeasuredHeight();
-        if (landscape != mLandscape) {
-            mLandscape = landscape;
-            if (mLandscape) {
-                toLandscape();
-                if (mChild instanceof LinearLayout) {
-                    mRotatedBackground = true;
-                    mBackground.setRotatedBackground(true);
-                    ((LinearLayout) mChild).setOrientation(LinearLayout.HORIZONTAL);
-                    swapDimens(mChild);
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        updateRotation();
+    }
+
+    private void updateRotation() {
+        int rotation = RotationUtils.getRotation(getContext());
+        if (rotation != mRotation) {
+            rotate(mRotation, rotation);
+            mRotation = rotation;
+        }
+    }
+
+    private void rotate(int from, int to) {
+        if (from != ROTATION_NONE && to != ROTATION_NONE) {
+            // Rather than handling this confusing case, just do 2 rotations.
+            rotate(from, ROTATION_NONE);
+            rotate(ROTATION_NONE, to);
+            return;
+        }
+        if (from == ROTATION_LANDSCAPE || to == ROTATION_SEASCAPE) {
+            rotateRight();
+        } else {
+            rotateLeft();
+        }
+        if (to != ROTATION_NONE) {
+            if (mChild instanceof LinearLayout) {
+                mRotatedBackground = true;
+                mBackground.setRotatedBackground(true);
+                LinearLayout linearLayout = (LinearLayout) mChild;
+                if (to == ROTATION_SEASCAPE) {
+                    swapOrder(linearLayout);
                 }
-            } else {
-                fromLandscape();
-                if (mChild instanceof LinearLayout) {
-                    mRotatedBackground = false;
-                    mBackground.setRotatedBackground(false);
-                    ((LinearLayout) mChild).setOrientation(LinearLayout.VERTICAL);
-                    swapDimens(mChild);
+                linearLayout.setOrientation(LinearLayout.HORIZONTAL);
+                swapDimens(this.mChild);
+            }
+        } else {
+            if (mChild instanceof LinearLayout) {
+                mRotatedBackground = false;
+                mBackground.setRotatedBackground(false);
+                LinearLayout linearLayout = (LinearLayout) mChild;
+                if (from == ROTATION_SEASCAPE) {
+                    swapOrder(linearLayout);
                 }
+                linearLayout.setOrientation(LinearLayout.VERTICAL);
+                swapDimens(mChild);
             }
         }
     }
 
-    private void fromLandscape() {
+    private void swapOrder(LinearLayout linearLayout) {
+        ArrayList<View> children = new ArrayList<>();
+        for (int i = 0; i < linearLayout.getChildCount(); i++) {
+            children.add(0, linearLayout.getChildAt(i));
+            linearLayout.removeViewAt(i);
+        }
+        children.forEach(v -> linearLayout.addView(v));
+    }
+
+    private void rotateRight() {
         rotateRight(this);
         rotateRight(mChild);
         swapDimens(this);
@@ -202,7 +251,7 @@
         return retGravity;
     }
 
-    private void toLandscape() {
+    private void rotateLeft() {
         rotateLeft(this);
         rotateLeft(mChild);
         swapDimens(this);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index 5aaa6c7..180b3ca 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -31,6 +31,7 @@
     void dozeTimeTick();
     boolean isPowerSaveActive();
     boolean isPulsingBlocked();
+    boolean isProvisioned();
 
     void startPendingIntentDismissingKeyguard(PendingIntent intent);
     void abortPulsing();
@@ -40,6 +41,7 @@
 
     void onDoubleTap(float x, float y);
 
+
     interface Callback {
         default void onNotificationHeadsUp() {}
         default void onPowerSaveChanged(boolean active) {}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 9981972..179f5b8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -172,14 +172,6 @@
         }
     }
 
-    private void onCarMode() {
-        mMachine.requestState(DozeMachine.State.FINISH);
-    }
-
-    private void onPowerSave() {
-        mMachine.requestState(DozeMachine.State.FINISH);
-    }
-
     @Override
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
         switch (newState) {
@@ -215,11 +207,10 @@
     }
 
     private void checkTriggersAtInit() {
-        if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR) {
-            onCarMode();
-        }
-        if (mDozeHost.isPowerSaveActive()) {
-            onPowerSave();
+        if (mUiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR
+                || mDozeHost.isPowerSaveActive()
+                || !mDozeHost.isProvisioned()) {
+            mMachine.requestState(DozeMachine.State.FINISH);
         }
     }
 
@@ -355,7 +346,7 @@
                 requestPulse(DozeLog.PULSE_REASON_INTENT, false /* performedProxCheck */);
             }
             if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
-                onCarMode();
+                mMachine.requestState(DozeMachine.State.FINISH);
             }
             if (Intent.ACTION_USER_SWITCHED.equals(intent.getAction())) {
                 mDozeSensors.onUserSwitched();
@@ -391,7 +382,7 @@
         @Override
         public void onPowerSaveChanged(boolean active) {
             if (active) {
-                onPowerSave();
+                mMachine.requestState(DozeMachine.State.FINISH);
             }
         }
     };
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index 1a8a474..31d41ac 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -682,10 +682,14 @@
 
     /** {@inheritDoc} */
     public void onClick(DialogInterface dialog, int which) {
-        if (!(mAdapter.getItem(which) instanceof SilentModeTriStateAction)) {
+        Action item = mAdapter.getItem(which);
+        if ((item instanceof PowerAction)
+                || (item instanceof RestartAction)) {
+            if (mDialog != null) mDialog.fadeOut();
+        } else if (!(item instanceof SilentModeTriStateAction)) {
             dialog.dismiss();
         }
-        mAdapter.getItem(which).onPress();
+        item.onPress();
     }
 
     /**
@@ -1321,6 +1325,17 @@
                     .start();
         }
 
+        public void fadeOut() {
+            mHardwareLayout.setTranslationX(0);
+            mHardwareLayout.setAlpha(1);
+            mListView.animate()
+                    .alpha(0)
+                    .translationX(getAnimTranslation())
+                    .setDuration(300)
+                    .setInterpolator(new LogAccelerateInterpolator())
+                    .start();
+        }
+
         private float getAnimTranslation() {
             return getContext().getResources().getDimension(
                     com.android.systemui.R.dimen.global_actions_panel_width) / 2;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
index 17a0d33..77c3bfa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSFactoryImpl.java
@@ -16,7 +16,9 @@
 
 import android.content.Context;
 import android.util.Log;
+import android.view.ContextThemeWrapper;
 
+import com.android.systemui.R;
 import com.android.systemui.plugins.qs.*;
 import com.android.systemui.plugins.qs.QSTileView;
 import com.android.systemui.qs.external.CustomTile;
@@ -78,7 +80,7 @@
 
     @Override
     public QSTileView createTileView(QSTile tile, boolean collapsedView) {
-        Context context = mHost.getContext();
+        Context context = new ContextThemeWrapper(mHost.getContext(), R.style.qs_theme);
         QSIconView icon = tile.createTileView(context);
         if (collapsedView) {
             return new QSTileBaseView(context, icon, collapsedView);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index cdd0ebc..6659650 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -144,22 +144,26 @@
     }
 
     public static void animateGrayScale(int fromColor, int toColor, ImageView iv) {
-        final float fromAlpha = Color.alpha(fromColor);
-        final float toAlpha = Color.alpha(toColor);
-        final float fromChannel = Color.red(fromColor);
-        final float toChannel = Color.red(toColor);
+        if (ValueAnimator.areAnimatorsEnabled()) {
+            final float fromAlpha = Color.alpha(fromColor);
+            final float toAlpha = Color.alpha(toColor);
+            final float fromChannel = Color.red(fromColor);
+            final float toChannel = Color.red(toColor);
 
-        ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
-        anim.setDuration(QS_ANIM_LENGTH);
+            ValueAnimator anim = ValueAnimator.ofFloat(0, 1);
+            anim.setDuration(QS_ANIM_LENGTH);
+            anim.addUpdateListener(animation -> {
+                float fraction = animation.getAnimatedFraction();
+                int alpha = (int) (fromAlpha + (toAlpha - fromAlpha) * fraction);
+                int channel = (int) (fromChannel + (toChannel - fromChannel) * fraction);
 
-        anim.addUpdateListener(animation -> {
-            float fraction = animation.getAnimatedFraction();
-            int alpha = (int) (fromAlpha + (toAlpha - fromAlpha) * fraction);
-            int channel = (int) (fromChannel + (toChannel - fromChannel) * fraction);
+                setTint(iv, Color.argb(alpha, channel, channel, channel));
+            });
 
-            setTint(iv, Color.argb(alpha, channel, channel, channel));
-        });
-        anim.start();
+            anim.start();
+        } else {
+            setTint(iv, toColor);
+        }
     }
 
     public static void setTint(ImageView iv, int color) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 36677a4..14afbfa 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -30,6 +30,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.settingslib.Utils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -271,7 +272,14 @@
                     int state = mController.getMaxConnectionState(device);
                     if (state == BluetoothProfile.STATE_CONNECTED) {
                         item.icon = R.drawable.ic_qs_bluetooth_connected;
-                        item.line2 = mContext.getString(R.string.quick_settings_connected);
+                        int batteryLevel = device.getBatteryLevel();
+                        if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+                            item.line2 = mContext.getString(
+                                    R.string.quick_settings_connected_battery_level,
+                                    Utils.formatPercentage(batteryLevel));
+                        } else {
+                            item.line2 = mContext.getString(R.string.quick_settings_connected);
+                        }
                         item.canDisconnect = true;
                         items.add(connectedDevices, item);
                         connectedDevices++;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 4de1214..fa16f8e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
@@ -42,9 +43,9 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.keyguard.LatencyTracker;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.Interpolators;
-import com.android.keyguard.LatencyTracker;
 import com.android.systemui.R;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
@@ -110,11 +111,10 @@
     private RecentsPackageMonitor mPackageMonitor;
     private Handler mHandler = new Handler();
     private long mLastTabKeyEventTime;
-    private int mLastDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
-    private int mLastDisplayDensity;
     private boolean mFinishedOnStartup;
     private boolean mIgnoreAltTabRelease;
     private boolean mIsVisible;
+    private Configuration mLastConfig;
 
     // Top level views
     private RecentsView mRecentsView;
@@ -333,16 +333,11 @@
         setContentView(R.layout.recents);
         takeKeyEvents(true);
         mRecentsView = findViewById(R.id.recents_view);
-        mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
-                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
-                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
         mScrimViews = new SystemBarScrimViews(this);
         getWindow().getAttributes().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
 
-        Configuration appConfiguration = Utilities.getAppConfiguration(this);
-        mLastDeviceOrientation = appConfiguration.orientation;
-        mLastDisplayDensity = appConfiguration.densityDpi;
+        mLastConfig = Utilities.getAppConfiguration(this);
         mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
         mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
             @Override
@@ -485,10 +480,15 @@
         Configuration newDeviceConfiguration = Utilities.getAppConfiguration(this);
         int numStackTasks = mRecentsView.getStack().getStackTaskCount();
         EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
-                mLastDeviceOrientation != newDeviceConfiguration.orientation,
-                mLastDisplayDensity != newDeviceConfiguration.densityDpi, numStackTasks > 0));
-        mLastDeviceOrientation = newDeviceConfiguration.orientation;
-        mLastDisplayDensity = newDeviceConfiguration.densityDpi;
+                mLastConfig.orientation != newDeviceConfiguration.orientation,
+                mLastConfig.densityDpi != newDeviceConfiguration.densityDpi, numStackTasks > 0));
+
+        int configDiff = mLastConfig.updateFrom(newDeviceConfiguration);
+
+        // Recreate activity if an overlay was enabled/disabled
+        if ((configDiff & ActivityInfo.CONFIG_ASSETS_PATHS) != 0) {
+            recreate();
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 521157d..d74970f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -43,14 +43,14 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
+import com.android.systemui.util.leak.RotationUtils;
 
 import java.util.ArrayList;
 
-public class ScreenPinningRequest implements View.OnClickListener {
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_LANDSCAPE;
+import static com.android.systemui.util.leak.RotationUtils.ROTATION_SEASCAPE;
 
-    private static final int ROTATION_NONE = 0;
-    private static final int ROTATION_LANDSCAPE = 1;
-    private static final int ROTATION_SEASCAPE = 2;
+public class ScreenPinningRequest implements View.OnClickListener {
 
     private final Context mContext;
 
@@ -160,7 +160,7 @@
             DisplayMetrics metrics = new DisplayMetrics();
             mWindowManager.getDefaultDisplay().getMetrics(metrics);
             float density = metrics.density;
-            int rotation = getRotation(mContext);
+            int rotation = RotationUtils.getRotation(mContext);
 
             inflateView(rotation);
             int bgColor = mContext.getColor(
@@ -202,19 +202,6 @@
             mContext.registerReceiver(mReceiver, filter);
         }
 
-        private int getRotation(Context context) {
-            Configuration config = mContext.getResources().getConfiguration();
-            int rot = context.getDisplay().getRotation();
-            if (config.smallestScreenWidthDp < 600) {
-                if (rot == Surface.ROTATION_90) {
-                    return ROTATION_LANDSCAPE;
-                } else if (rot == Surface.ROTATION_270) {
-                    return ROTATION_SEASCAPE;
-                }
-            }
-            return ROTATION_NONE;
-        }
-
         private void inflateView(int rotation) {
             // We only want this landscape orientation on <600dp, so rather than handle
             // resource overlay for -land and -sw600dp-land, just inflate this
@@ -287,14 +274,14 @@
 
         protected void onConfigurationChanged() {
             removeAllViews();
-            inflateView(getRotation(mContext));
+            inflateView(RotationUtils.getRotation(mContext));
         }
 
         private final Runnable mUpdateLayoutRunnable = new Runnable() {
             @Override
             public void run() {
                 if (mLayout != null && mLayout.getParent() != null) {
-                    mLayout.setLayoutParams(getRequestLayoutParams(getRotation(mContext)));
+                    mLayout.setLayoutParams(getRequestLayoutParams(RotationUtils.getRotation(mContext)));
                 }
             }
         };
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 21dfe8c..968b77f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -400,8 +400,8 @@
             view.draw(c);
         }
         node.end(c);
-        return ThreadedRenderer.createHardwareBitmap(node, bufferWidth, bufferHeight)
-                .createGraphicBufferHandle();
+        Bitmap hwBitmap = ThreadedRenderer.createHardwareBitmap(node, bufferWidth, bufferHeight);
+        return hwBitmap.createGraphicBufferHandle();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 9ca756c..c1c41be0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -151,6 +151,12 @@
         mColorExtractor = Dependency.get(SysuiColorExtractor.class);
 
         LayoutInflater inflater = LayoutInflater.from(context);
+
+        mEmptyView = (TextView) inflater.inflate(R.layout.recents_empty, this, false);
+        addView(mEmptyView);
+
+        boolean usingDarkText =
+                Color.luminance(mEmptyView.getTextColors().getDefaultColor()) < 0.5f;
         if (RecentsDebugFlags.Static.EnableStackActionButton) {
             mStackActionButton = (TextView) inflater.inflate(R.layout.recents_stack_action_button,
                     this, false);
@@ -160,10 +166,21 @@
                     EventBus.getDefault().send(new DismissAllTaskViewsEvent());
                 }
             });
+            // Disable black shadow if text color is already dark.
+            if (usingDarkText) {
+                mStackActionButton.setShadowLayer(0, 0, 0, 0);
+            }
             addView(mStackActionButton);
         }
-        mEmptyView = (TextView) inflater.inflate(R.layout.recents_empty, this, false);
-        addView(mEmptyView);
+
+        // Let's also require dark status and nav bars if the text is dark
+        int systemBarsStyle = usingDarkText ? View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR |
+                View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR : 0;
+
+        setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
+                View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
+                View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION |
+                systemBarsStyle);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 674a61c..df1ffda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -168,8 +168,7 @@
                         distance = mTranslationOnDown + distance;
                         distance = Math.max(0, distance);
                     }
-                    setTranslation(distance, false /* isReset */, false /* animateReset */,
-                            false /* force */);
+                    setTranslation(distance, false /* isReset */, false /* animateReset */);
                 }
                 break;
 
@@ -374,12 +373,11 @@
         targetView.finishAnimation(velocity, mAnimationEndRunnable);
     }
 
-    private void setTranslation(float translation, boolean isReset, boolean animateReset,
-            boolean force) {
+    private void setTranslation(float translation, boolean isReset, boolean animateReset) {
         translation = rightSwipePossible() ? translation : Math.max(0, translation);
         translation = leftSwipePossible() ? translation : Math.min(0, translation);
         float absTranslation = Math.abs(translation);
-        if (translation != mTranslation || isReset || force) {
+        if (translation != mTranslation || isReset) {
             KeyguardAffordanceView targetView = translation > 0 ? mLeftIcon : mRightIcon;
             KeyguardAffordanceView otherView = translation > 0 ? mRightIcon : mLeftIcon;
             float alpha = absTranslation / getMinTranslationAmount();
@@ -394,15 +392,15 @@
             boolean slowAnimation = isReset && isBelowFalsingThreshold();
             if (!isReset) {
                 updateIcon(targetView, radius, alpha + fadeOutAlpha * targetView.getRestingAlpha(),
-                        false, false, force, false);
+                        false, false, false, false);
             } else {
                 updateIcon(targetView, 0.0f, fadeOutAlpha * targetView.getRestingAlpha(),
-                        animateIcons, slowAnimation, force, forceNoCircleAnimation);
+                        animateIcons, slowAnimation, true /* isReset */, forceNoCircleAnimation);
             }
             updateIcon(otherView, 0.0f, fadeOutAlpha * otherView.getRestingAlpha(),
-                    animateIcons, slowAnimation, force, forceNoCircleAnimation);
+                    animateIcons, slowAnimation, isReset, forceNoCircleAnimation);
             updateIcon(mCenterIcon, 0.0f, fadeOutAlpha * mCenterIcon.getRestingAlpha(),
-                    animateIcons, slowAnimation, force, forceNoCircleAnimation);
+                    animateIcons, slowAnimation, isReset, forceNoCircleAnimation);
 
             mTranslation = translation;
         }
@@ -510,12 +508,8 @@
     }
 
     public void reset(boolean animate) {
-        reset(animate, false /* force */);
-    }
-
-    public void reset(boolean animate, boolean force) {
         cancelAnimation();
-        setTranslation(0.0f, true, animate, force);
+        setTranslation(0.0f, true /* isReset */, animate);
         mMotionCancelled = true;
         if (mSwipingInProgress) {
             mCallback.onSwipingAborted();
@@ -523,10 +517,6 @@
         }
     }
 
-    public void resetImmediately() {
-        reset(false /* animate */, true /* force */);
-    }
-
     public boolean isSwipingInProgress() {
         return mSwipingInProgress;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index a4dfcd8..e9aa6d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -254,6 +254,7 @@
         mFlashlightController = Dependency.get(FlashlightController.class);
         mAccessibilityController = Dependency.get(AccessibilityController.class);
         mAssistManager = Dependency.get(AssistManager.class);
+        mLockIcon.setAccessibilityController(mAccessibilityController);
         updateLeftAffordance();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 5116414..bbcf6c7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2573,7 +2573,7 @@
     public void setTouchDisabled(boolean disabled) {
         super.setTouchDisabled(disabled);
         if (disabled && mAffordanceHelper.isSwipingInProgress() && !mIsLaunchTransitionRunning) {
-            mAffordanceHelper.resetImmediately();
+            mAffordanceHelper.reset(false /* animate */);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index bcba789..2217133 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1150,7 +1150,6 @@
             ExtensionFragmentListener.attachExtensonToFragment(container, QS.TAG, R.id.qs_frame,
                     Dependency.get(ExtensionController.class).newExtension(QS.class)
                             .withPlugin(QS.class)
-                            .withUiMode(UI_MODE_TYPE_CAR, () -> new QSFragment())
                             .withDefault(() -> new QSFragment())
                             .build());
             final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
@@ -1318,6 +1317,9 @@
                 .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
         mKeyguardIndicationController.setVisible(mState == StatusBarState.KEYGUARD);
         mKeyguardIndicationController.setDozing(mDozing);
+        if (mBrightnessMirrorController != null) {
+            mBrightnessMirrorController.onOverlayChanged();
+        }
     }
 
     protected void reevaluateStyles() {
@@ -3757,7 +3759,7 @@
 
     // SystemUIService notifies SystemBars of configuration changes, which then calls down here
     @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
+    public void onConfigChanged(Configuration newConfig) {
         updateResources();
         updateDisplaySize(); // populates mDisplayMetrics
 
@@ -4207,7 +4209,7 @@
         }
         if (shouldBeKeyguard) {
             showKeyguardImpl();
-        } else if (!shouldBeKeyguard && mIsKeyguard) {
+        } else {
             return hideKeyguardImpl();
         }
         return false;
@@ -5369,6 +5371,12 @@
         }
 
         @Override
+        public boolean isProvisioned() {
+            return mDeviceProvisionedController.isDeviceProvisioned()
+                    && mDeviceProvisionedController.isCurrentUserSetup();
+        }
+
+        @Override
         public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
             StatusBar.this.startPendingIntentDismissingKeyguard(intent);
         }
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 ad406c7..ab55b23 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BrightnessMirrorController.java
@@ -84,7 +84,6 @@
                 .setInterpolator(Interpolators.ALPHA_IN);
     }
 
-
     public void setLocation(View original) {
         original.getLocationInWindow(mInt2Cache);
 
@@ -115,7 +114,15 @@
         mBrightnessMirror.setLayoutParams(lp);
     }
 
+    public void onOverlayChanged() {
+        reinflate();
+    }
+
     public void onDensityOrFontScaleChanged() {
+        reinflate();
+    }
+
+    private void reinflate() {
         int index = mStatusBarWindow.indexOfChild(mBrightnessMirror);
         mStatusBarWindow.removeView(mBrightnessMirror);
         mBrightnessMirror = LayoutInflater.from(mBrightnessMirror.getContext()).inflate(
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 2981b39..74523e2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -2589,9 +2589,6 @@
         }
         updateAnimationState(false, child);
 
-        // Make sure the clipRect we might have set is removed
-        expandableView.setClipTopAmount(0);
-
         focusNextViewIfFocused(child);
     }
 
@@ -3038,10 +3035,6 @@
     private void generateChildRemovalEvents() {
         for (View child : mChildrenToRemoveAnimated) {
             boolean childWasSwipedOut = mSwipedOutViews.contains(child);
-            int animationType = childWasSwipedOut
-                    ? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
-                    : AnimationEvent.ANIMATION_TYPE_REMOVE;
-            AnimationEvent event = new AnimationEvent(child, animationType);
 
             // we need to know the view after this one
             float removedTranslation = child.getTranslationY();
@@ -3052,7 +3045,16 @@
                     removedTranslation = row.getTranslationWhenRemoved();
                     ignoreChildren = false;
                 }
+                childWasSwipedOut |= Math.abs(row.getTranslation()) == row.getWidth();
             }
+            if (!childWasSwipedOut) {
+                Rect clipBounds = child.getClipBounds();
+                childWasSwipedOut = clipBounds.height() == 0;
+            }
+            int animationType = childWasSwipedOut
+                    ? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
+                    : AnimationEvent.ANIMATION_TYPE_REMOVE;
+            AnimationEvent event = new AnimationEvent(child, animationType);
             event.viewAfterChangingView = getFirstChildBelowTranlsationY(removedTranslation,
                     ignoreChildren);
             mAnimationEvents.add(event);
@@ -3360,15 +3362,29 @@
         if (!mIsExpanded) {
             setOwnScrollY(0);
             mStatusBar.resetUserExpandedStates();
+            clearTemporaryViews();
+            clearUserLockedViews();
+        }
+    }
 
-            // lets make sure nothing is in the overlay / transient anymore
-            clearTemporaryViews(this);
-            for (int i = 0; i < getChildCount(); i++) {
-                ExpandableView child = (ExpandableView) getChildAt(i);
-                if (child instanceof ExpandableNotificationRow) {
-                    ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                    clearTemporaryViews(row.getChildrenContainer());
-                }
+    private void clearUserLockedViews() {
+        for (int i = 0; i < getChildCount(); i++) {
+            ExpandableView child = (ExpandableView) getChildAt(i);
+            if (child instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+                row.setUserLocked(false);
+            }
+        }
+    }
+
+    private void clearTemporaryViews() {
+        // lets make sure nothing is in the overlay / transient anymore
+        clearTemporaryViews(this);
+        for (int i = 0; i < getChildCount(); i++) {
+            ExpandableView child = (ExpandableView) getChildAt(i);
+            if (child instanceof ExpandableNotificationRow) {
+                ExpandableNotificationRow row = (ExpandableNotificationRow) child;
+                clearTemporaryViews(row.getChildrenContainer());
             }
         }
     }
@@ -3403,6 +3419,7 @@
         if (changed) {
             if (!mIsExpanded) {
                 mGroupManager.collapseAllGroups();
+                mExpandHelper.cancelImmediately();
             }
             updateNotificationAnimationStates();
             updateChronometers();
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
new file mode 100644
index 0000000..ad20900
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.util.leak;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.view.Surface;
+
+public class RotationUtils {
+
+    public static final int ROTATION_NONE = 0;
+    public static final int ROTATION_LANDSCAPE = 1;
+    public static final int ROTATION_SEASCAPE = 2;
+
+    public static int getRotation(Context context) {
+        Configuration config = context.getResources().getConfiguration();
+        int rot = context.getDisplay().getRotation();
+        if (config.smallestScreenWidthDp < 600) {
+            if (rot == Surface.ROTATION_90) {
+                return ROTATION_LANDSCAPE;
+            } else if (rot == Surface.ROTATION_270) {
+                return ROTATION_SEASCAPE;
+            }
+        }
+        return ROTATION_NONE;
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index 2345110..8ff9fa9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -72,6 +72,11 @@
     }
 
     @Override
+    public boolean isProvisioned() {
+        return false;
+    }
+
+    @Override
     public void startPendingIntentDismissingKeyguard(PendingIntent intent) {
         throw new RuntimeException("not implemented");
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 0937ce2..c0de004 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -19,12 +19,13 @@
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
 import com.android.internal.app.NightDisplayController;
 import com.android.systemui.Prefs;
 import com.android.systemui.Prefs.Key;
-
-import android.support.test.filters.SmallTest;
-import android.testing.AndroidTestingRunner;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.qs.QSTileHost;
 
@@ -35,6 +36,7 @@
 import org.mockito.Mockito;
 
 @RunWith(AndroidTestingRunner.class)
+@RunWithLooper
 @SmallTest
 public class AutoTileManagerTest extends SysuiTestCase {
 
diff --git a/packages/overlays/SysuiDarkThemeOverlay/AndroidManifest.xml b/packages/overlays/SysuiDarkThemeOverlay/AndroidManifest.xml
index ba1c91c..8b6ee2b 100644
--- a/packages/overlays/SysuiDarkThemeOverlay/AndroidManifest.xml
+++ b/packages/overlays/SysuiDarkThemeOverlay/AndroidManifest.xml
@@ -2,7 +2,7 @@
     package="com.android.systemui.theme.dark"
     android:versionCode="1"
     android:versionName="1.0">
-    <overlay android:targetPackage="android" android:priority="1"/>
+    <overlay android:targetPackage="com.android.systemui" android:priority="1"/>
 
     <application android:label="@string/sysui_overlay_dark" android:hasCode="false"/>
 </manifest>
diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml
new file mode 100644
index 0000000..0c1b0ef
--- /dev/null
+++ b/packages/overlays/SysuiDarkThemeOverlay/res/values/styles.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="qs_base" parent="android:Theme.DeviceDefault">
+        <item name="android:colorPrimary">@*android:color/primary_device_default_settings</item>
+        <item name="android:colorPrimaryDark">@*android:color/primary_dark_device_default_settings</item>
+        <item name="android:colorSecondary">@*android:color/secondary_device_default_settings</item>
+        <item name="android:colorAccent">@*android:color/accent_device_default_dark</item>
+        <item name="android:colorControlNormal">?android:attr/textColorPrimary</item>
+        <item name="android:colorBackgroundFloating">#000</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/packages/overlays/SysuiDarkThemeOverlay/res/values/themes_device_defaults.xml b/packages/overlays/SysuiDarkThemeOverlay/res/values/themes_device_defaults.xml
deleted file mode 100644
index 7e2b955..0000000
--- a/packages/overlays/SysuiDarkThemeOverlay/res/values/themes_device_defaults.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <style name="Theme.DeviceDefault.QuickSettings" parent="android:Theme.DeviceDefault">
-        <item name="android:colorPrimary">@*android:color/primary_device_default_settings</item>
-        <item name="android:colorPrimaryDark">@*android:color/primary_dark_device_default_settings</item>
-        <!-- textColorPrimaryInverse is used on the lock screen and this means that we can't just
-        invert text colors otherwise we won't have contrast on the keyguard -->
-        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_dark</item>
-        <!-- same for textColorSecondaryInverse -->
-        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_dark</item>
-        <item name="android:colorSecondary">@*android:color/secondary_device_default_settings</item>
-        <item name="android:colorAccent">@*android:color/accent_device_default_dark</item>
-        <item name="android:colorControlNormal">?android:attr/textColorPrimary</item>
-        <item name="android:colorBackgroundFloating">#000</item>
-    </style>
-</resources>
\ No newline at end of file
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml
index 1745b4c..0a8749c 100644
--- a/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml
+++ b/packages/overlays/SysuiLightWallpaperThemeOverlay/AndroidManifest.xml
@@ -2,7 +2,7 @@
     package="com.android.systemui.theme.lightwallpaper"
     android:versionCode="1"
     android:versionName="1.0">
-    <overlay android:targetPackage="android" android:priority="2"/>
+    <overlay android:targetPackage="com.android.systemui" android:priority="2"/>
 
     <application android:label="@string/sysui_overlay_light" android:hasCode="false"/>
 </manifest>
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/styles.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/styles.xml
new file mode 100644
index 0000000..53912b5
--- /dev/null
+++ b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/styles.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <style name="systemui_base" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
+        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_light</item>
+        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_light</item>
+    </style>
+
+    <style name="RecentsBase" parent="@android:style/Theme.Material">
+        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_light</item>
+        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_light</item>
+    </style>
+</resources>
\ No newline at end of file
diff --git a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/themes_device_defaults.xml b/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/themes_device_defaults.xml
deleted file mode 100644
index 877ebf8..0000000
--- a/packages/overlays/SysuiLightWallpaperThemeOverlay/res/values/themes_device_defaults.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <style name="Theme.DeviceDefault.QuickSettings" parent="android:Theme.DeviceDefault.Light">
-        <item name="android:textColorPrimaryInverse">@*android:color/primary_text_material_light</item>
-        <item name="android:textColorSecondaryInverse">@*android:color/secondary_text_material_light</item>
-    </style>
-</resources>
\ No newline at end of file
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 224845c..c4e0e52 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -210,13 +210,6 @@
     // See Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS
     private final int mReleasePendingIntentDelayMs;
 
-    // Driver specific constants used to select packets received via
-    // WiFi that caused the phone to exit sleep state. Currently there
-    // is only one kernel implementation so we can get away with
-    // constants.
-    private static final int mWakeupPacketMark = 0x80000000;
-    private static final int mWakeupPacketMask = 0x80000000;
-
     private MockableSystemProperties mSystemProperties;
 
     private Tethering mTethering;
@@ -2282,6 +2275,10 @@
             notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
             mKeepaliveTracker.handleStopAllKeepalives(nai,
                     ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
+            for (String iface : nai.linkProperties.getAllInterfaceNames()) {
+                // Disable wakeup packet monitoring for each interface.
+                wakeupModifyInterface(iface, nai.networkCapabilities, false);
+            }
             nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
             mNetworkAgentInfos.remove(msg.replyTo);
             updateClat(null, nai.linkProperties, nai);
@@ -4401,22 +4398,35 @@
         }
     }
 
-    private void wakeupAddInterface(String iface, NetworkCapabilities caps) throws RemoteException {
+    private void wakeupModifyInterface(String iface, NetworkCapabilities caps, boolean add) {
         // Marks are only available on WiFi interaces. Checking for
         // marks on unsupported interfaces is harmless.
         if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
             return;
         }
-        mNetd.getNetdService().wakeupAddInterface(
-            iface, "iface:" + iface, mWakeupPacketMark, mWakeupPacketMask);
-    }
 
-    private void wakeupDelInterface(String iface, NetworkCapabilities caps) throws RemoteException {
-        if (!caps.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
+        int mark = mContext.getResources().getInteger(
+            com.android.internal.R.integer.config_networkWakeupPacketMark);
+        int mask = mContext.getResources().getInteger(
+            com.android.internal.R.integer.config_networkWakeupPacketMask);
+
+        // Mask/mark of zero will not detect anything interesting.
+        // Don't install rules unless both values are nonzero.
+        if (mark == 0 || mask == 0) {
             return;
         }
-        mNetd.getNetdService().wakeupDelInterface(
-            iface, "iface:" + iface, mWakeupPacketMark, mWakeupPacketMask);
+
+        final String prefix = "iface:" + iface;
+        try {
+            if (add) {
+                mNetd.getNetdService().wakeupAddInterface(iface, prefix, mark, mask);
+            } else {
+                mNetd.getNetdService().wakeupDelInterface(iface, prefix, mark, mask);
+            }
+        } catch (Exception e) {
+            loge("Exception modifying wakeup packet monitoring: " + e);
+        }
+
     }
 
     private void updateInterfaces(LinkProperties newLp, LinkProperties oldLp, int netId,
@@ -4431,7 +4441,7 @@
             try {
                 if (DBG) log("Adding iface " + iface + " to network " + netId);
                 mNetd.addInterfaceToNetwork(iface, netId);
-                wakeupAddInterface(iface, caps);
+                wakeupModifyInterface(iface, caps, true);
             } catch (Exception e) {
                 loge("Exception adding interface: " + e);
             }
@@ -4439,8 +4449,8 @@
         for (String iface : interfaceDiff.removed) {
             try {
                 if (DBG) log("Removing iface " + iface + " from network " + netId);
+                wakeupModifyInterface(iface, caps, false);
                 mNetd.removeInterfaceFromNetwork(iface, netId);
-                wakeupDelInterface(iface, caps);
             } catch (Exception e) {
                 loge("Exception removing interface: " + e);
             }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 9cde9859..0295f18 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -2882,8 +2882,9 @@
                     } else {
                         // If a new task is being launched, then mark the existing top activity as
                         // supporting picture-in-picture while pausing
-                        if (focusedTopActivity != null &&
-                                focusedTopActivity.getStack().getStackId() != PINNED_STACK_ID) {
+                        if (focusedTopActivity != null
+                                && focusedTopActivity.getStackId() != PINNED_STACK_ID
+                                && r.getStackId() != ASSISTANT_STACK_ID) {
                             focusedTopActivity.supportsPictureInPictureWhilePausing = true;
                         }
                         transit = TRANSIT_TASK_OPEN;
@@ -4549,7 +4550,8 @@
         }
         // If a new task is moved to the front, then mark the existing top activity as supporting
         // picture-in-picture while paused
-        if (topActivity != null && topActivity.getStack().getStackId() != PINNED_STACK_ID) {
+        if (topActivity != null && topActivity.getStackId() != PINNED_STACK_ID
+                && tr.getStackId() != ASSISTANT_STACK_ID) {
             topActivity.supportsPictureInPictureWhilePausing = true;
         }
 
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index e2956dd..b657335 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -16,6 +16,7 @@
 
 package com.android.server.connectivity;
 
+import static android.hardware.usb.UsbManager.USB_CONFIGURED;
 import static android.hardware.usb.UsbManager.USB_CONNECTED;
 import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
 import static android.net.ConnectivityManager.getNetworkTypeName;
@@ -703,7 +704,7 @@
 
     private void showTetheredNotification(int id) {
         NotificationManager notificationManager =
-                (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         if (notificationManager == null) {
             return;
         }
@@ -764,7 +765,7 @@
 
     private void clearTetheredNotification() {
         NotificationManager notificationManager =
-            (NotificationManager)mContext.getSystemService(Context.NOTIFICATION_SERVICE);
+            (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
         if (notificationManager != null && mLastNotificationId != 0) {
             notificationManager.cancelAsUser(null, mLastNotificationId,
                     UserHandle.ALL);
@@ -803,11 +804,37 @@
 
         private void handleUsbAction(Intent intent) {
             final boolean usbConnected = intent.getBooleanExtra(USB_CONNECTED, false);
+            final boolean usbConfigured = intent.getBooleanExtra(USB_CONFIGURED, false);
             final boolean rndisEnabled = intent.getBooleanExtra(USB_FUNCTION_RNDIS, false);
+
+            mLog.log(String.format("USB bcast connected:%s configured:%s rndis:%s",
+                    usbConnected, usbConfigured, rndisEnabled));
+
+            // There are three types of ACTION_USB_STATE:
+            //
+            //     - DISCONNECTED (USB_CONNECTED and USB_CONFIGURED are 0)
+            //       Meaning: USB connection has ended either because of
+            //       software reset or hard unplug.
+            //
+            //     - CONNECTED (USB_CONNECTED is 1, USB_CONFIGURED is 0)
+            //       Meaning: the first stage of USB protocol handshake has
+            //       occurred but it is not complete.
+            //
+            //     - CONFIGURED (USB_CONNECTED and USB_CONFIGURED are 1)
+            //       Meaning: the USB handshake is completely done and all the
+            //       functions are ready to use.
+            //
+            // For more explanation, see b/62552150 .
+            if (usbConnected && !usbConfigured) {
+                // Nothing for us to do here.
+                // TODO: consider ignoring DISCONNECTED broadcasts as well.
+                return;
+            }
+
             synchronized (Tethering.this.mPublicSync) {
                 mRndisEnabled = rndisEnabled;
                 // start tethering if we have a request pending
-                if (usbConnected && mRndisEnabled && mUsbTetherRequested) {
+                if (usbConfigured && mRndisEnabled && mUsbTetherRequested) {
                     tetherMatchingInterfaces(
                             IControlsTethering.STATE_TETHERED,
                             ConnectivityManager.TETHERING_USB);
@@ -983,7 +1010,7 @@
 
     public int setUsbTethering(boolean enable) {
         if (VDBG) Log.d(TAG, "setUsbTethering(" + enable + ")");
-        UsbManager usbManager = mContext.getSystemService(UsbManager.class);
+        UsbManager usbManager = (UsbManager) mContext.getSystemService(Context.USB_SERVICE);
 
         synchronized (mPublicSync) {
             if (enable) {
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
index 78487b7..20ec206 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadController.java
@@ -58,7 +58,12 @@
     }
 
     public void start() {
-        if (isOffloadDisabled() || started()) return;
+        if (started()) return;
+
+        if (isOffloadDisabled()) {
+            mLog.i("tethering offload disabled");
+            return;
+        }
 
         if (!mConfigInitialized) {
             mConfigInitialized = mHwInterface.initOffloadConfig();
diff --git a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
index 1fc1684..09fd96b 100644
--- a/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
+++ b/services/core/java/com/android/server/connectivity/tethering/OffloadHardwareInterface.java
@@ -76,6 +76,10 @@
             }
         }
 
+        final String logmsg = String.format("initOffloadControl(%s)",
+                (controlCb == null) ? "null"
+                        : "0x" + Integer.toHexString(System.identityHashCode(controlCb)));
+
         mTetheringOffloadCallback = new TetheringOffloadCallback(mHandler, mControlCallback);
         final CbResults results = new CbResults();
         try {
@@ -86,11 +90,11 @@
                         results.errMsg = errMsg;
                     });
         } catch (RemoteException e) {
-            mLog.e("failed to initOffload: " + e);
+            record(logmsg, e);
             return false;
         }
 
-        if (!results.success) mLog.e("initOffload failed: " + results.errMsg);
+        record(logmsg, results);
         return results.success;
     }
 
@@ -108,14 +112,18 @@
         mOffloadControl = null;
         mTetheringOffloadCallback = null;
         mControlCallback = null;
+        mLog.log("stopOffloadControl()");
     }
 
     public boolean setUpstreamParameters(
             String iface, String v4addr, String v4gateway, ArrayList<String> v6gws) {
-        iface = iface != null ? iface : NO_INTERFACE_NAME;
-        v4addr = v4addr != null ? v4addr : NO_IPV4_ADDRESS;
-        v4gateway = v4gateway != null ? v4gateway : NO_IPV4_GATEWAY;
-        v6gws = v6gws != null ? v6gws : new ArrayList<>();
+        iface = (iface != null) ? iface : NO_INTERFACE_NAME;
+        v4addr = (v4addr != null) ? v4addr : NO_IPV4_ADDRESS;
+        v4gateway = (v4gateway != null) ? v4gateway : NO_IPV4_GATEWAY;
+        v6gws = (v6gws != null) ? v6gws : new ArrayList<>();
+
+        final String logmsg = String.format("setUpstreamParameters(%s, %s, %s, [%s])",
+                iface, v4addr, v4gateway, String.join(",", v6gws));
 
         final CbResults results = new CbResults();
         try {
@@ -126,14 +134,27 @@
                         results.errMsg = errMsg;
                     });
         } catch (RemoteException e) {
-            mLog.e("failed to setUpstreamParameters: " + e);
+            record(logmsg, e);
             return false;
         }
 
-        if (!results.success) mLog.e("setUpstreamParameters failed: " + results.errMsg);
+        record(logmsg, results);
         return results.success;
     }
 
+    private void record(String msg, Throwable t) {
+        mLog.e(msg + " -> exception: " + t);
+    }
+
+    private void record(String msg, CbResults results) {
+        final String logmsg = msg + " -> " + results;
+        if (!results.success) {
+            mLog.e(logmsg);
+        } else {
+            mLog.log(logmsg);
+        }
+    }
+
     private static class TetheringOffloadCallback extends ITetheringOffloadCallback.Stub {
         public final Handler handler;
         public final ControlCallback controlCb;
@@ -162,5 +183,13 @@
     private static class CbResults {
         boolean success;
         String errMsg;
+
+        public String toString() {
+            if (success) {
+                return "ok";
+            } else {
+                return "fail: " + errMsg;
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index ebb9450..c6ec287 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -19,6 +19,7 @@
 import android.animation.ArgbEvaluator;
 import android.animation.ValueAnimator;
 import android.app.ActivityManager;
+import android.app.ActivityThread;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -79,7 +80,7 @@
     boolean mVrModeEnabled = false;
 
     public ImmersiveModeConfirmation(Context context) {
-        mContext = context;
+        mContext = ActivityThread.currentActivityThread().getSystemUiContext();
         mHandler = new H();
         mShowDelayMs = getNavBarExitDuration() * 3;
         mPanicThresholdMs = context.getResources()
diff --git a/services/core/java/com/android/server/power/ShutdownThread.java b/services/core/java/com/android/server/power/ShutdownThread.java
index 02f2afc..56612ad 100644
--- a/services/core/java/com/android/server/power/ShutdownThread.java
+++ b/services/core/java/com/android/server/power/ShutdownThread.java
@@ -23,14 +23,17 @@
 import android.app.ProgressDialog;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.IBluetoothManager;
-import android.media.AudioAttributes;
-import android.nfc.NfcAdapter;
-import android.nfc.INfcAdapter;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.om.IOverlayManager;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.media.AudioAttributes;
+import android.nfc.INfcAdapter;
+import android.nfc.NfcAdapter;
 import android.os.FileUtils;
 import android.os.Handler;
 import android.os.PowerManager;
@@ -39,24 +42,21 @@
 import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
+import android.os.SystemVibrator;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.Vibrator;
-import android.os.SystemVibrator;
-import android.os.storage.IStorageShutdownObserver;
 import android.os.storage.IStorageManager;
-import android.system.ErrnoException;
-import android.system.Os;
-
+import android.os.storage.IStorageShutdownObserver;
+import android.util.Log;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.ProgressBar;
+import android.widget.TextView;
 import com.android.internal.telephony.ITelephony;
 import com.android.server.pm.PackageManagerService;
 
-import android.util.Log;
-import android.view.WindowManager;
-
-import java.io.BufferedReader;
 import java.io.File;
-import java.io.FileReader;
 import java.io.IOException;
 
 public final class ShutdownThread extends Thread {
@@ -243,15 +243,7 @@
         shutdownInner(context, confirm);
     }
 
-    private static void beginShutdownSequence(Context context) {
-        synchronized (sIsStartedGuard) {
-            if (sIsStarted) {
-                Log.d(TAG, "Shutdown sequence already running, returning.");
-                return;
-            }
-            sIsStarted = true;
-        }
-
+    private static ProgressDialog showShutdownDialog(Context context) {
         // Throw up a system dialog to indicate the device is rebooting / shutting down.
         ProgressDialog pd = new ProgressDialog(context);
 
@@ -303,6 +295,32 @@
             pd.setMessage(context.getText(
                         com.android.internal.R.string.reboot_to_reset_message));
             pd.setIndeterminate(true);
+        } else if (mReason != null && mReason.equals(PowerManager.SHUTDOWN_USER_REQUESTED)) {
+            Dialog d = new Dialog(context);
+            d.setContentView(com.android.internal.R.layout.shutdown_dialog);
+            d.setCancelable(false);
+
+            int color = Color.WHITE;
+            try {
+                IOverlayManager service = IOverlayManager.Stub.asInterface(
+                        ServiceManager.getService(Context.OVERLAY_SERVICE));
+                if (service.getOverlayInfo("com.android.systemui.theme.lightwallpaper", 0).isEnabled()) {
+                    color = Color.BLACK;
+                }
+            } catch (Exception e) {
+                // Shutdown UI really shouldn't crash or have strict dependencies on other services.
+                Log.w(TAG, "Problem getting overlay state", e);
+            }
+            ProgressBar bar = d.findViewById(com.android.internal.R.id.progress);
+            bar.getIndeterminateDrawable().setTint(color);
+            ((TextView) d.findViewById(com.android.internal.R.id.text1)).setTextColor(color);
+            d.getWindow().getAttributes().width = ViewGroup.LayoutParams.MATCH_PARENT;
+            d.getWindow().getAttributes().height = ViewGroup.LayoutParams.MATCH_PARENT;
+            d.getWindow().setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY);
+            d.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
+            d.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
+            d.show();
+            return null;
         } else {
             pd.setTitle(context.getText(com.android.internal.R.string.power_off));
             pd.setMessage(context.getText(com.android.internal.R.string.shutdown_progress));
@@ -312,8 +330,19 @@
         pd.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
 
         pd.show();
+        return pd;
+    }
 
-        sInstance.mProgressDialog = pd;
+    private static void beginShutdownSequence(Context context) {
+        synchronized (sIsStartedGuard) {
+            if (sIsStarted) {
+                Log.d(TAG, "Shutdown sequence already running, returning.");
+                return;
+            }
+            sIsStarted = true;
+        }
+
+        sInstance.mProgressDialog = showShutdownDialog(context);
         sInstance.mContext = context;
         sInstance.mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
 
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 35e4e58c..8ce59ed 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -67,7 +67,6 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -589,22 +588,20 @@
     }
 
     private void maybeEnableFactoryTrustAgents(LockPatternUtils utils, int userId) {
+        if (0 != Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                Settings.Secure.TRUST_AGENTS_INITIALIZED, 0, userId)) {
+            return;
+        }
+        PackageManager pm = mContext.getPackageManager();
+        List<ResolveInfo> resolveInfos = resolveAllowedTrustAgents(pm, userId);
         ComponentName defaultAgent = getDefaultFactoryTrustAgent(mContext);
         boolean shouldUseDefaultAgent = defaultAgent != null;
+        ArraySet<ComponentName> discoveredAgents = new ArraySet<>();
 
         if (shouldUseDefaultAgent) {
+            discoveredAgents.add(defaultAgent);
             Log.i(TAG, "Enabling " + defaultAgent + " because it is a default agent.");
-            utils.setEnabledTrustAgents(Collections.singleton(defaultAgent), userId);
         } else { // A default agent is not set; perform regular trust agent discovery
-            if (0 != Settings.Secure.getIntForUser(mContext.getContentResolver(),
-                    Settings.Secure.TRUST_AGENTS_INITIALIZED, 0, userId)) {
-                return;
-            }
-            PackageManager pm = mContext.getPackageManager();
-            List<ResolveInfo> resolveInfos = resolveAllowedTrustAgents(pm, userId);
-
-            ArraySet<ComponentName> discoveredAgents = new ArraySet<>();
-
             for (ResolveInfo resolveInfo : resolveInfos) {
                 ComponentName componentName = getComponentName(resolveInfo);
                 int applicationInfoFlags = resolveInfo.serviceInfo.applicationInfo.flags;
@@ -615,13 +612,13 @@
                 }
                 discoveredAgents.add(componentName);
             }
-
-            List<ComponentName> previouslyEnabledAgents = utils.getEnabledTrustAgents(userId);
-            if (previouslyEnabledAgents != null) {
-                discoveredAgents.addAll(previouslyEnabledAgents);
-            }
-            utils.setEnabledTrustAgents(discoveredAgents, userId);
         }
+
+        List<ComponentName> previouslyEnabledAgents = utils.getEnabledTrustAgents(userId);
+        if (previouslyEnabledAgents != null) {
+            discoveredAgents.addAll(previouslyEnabledAgents);
+        }
+        utils.setEnabledTrustAgents(discoveredAgents, userId);
         Settings.Secure.putIntForUser(mContext.getContentResolver(),
                 Settings.Secure.TRUST_AGENTS_INITIALIZED, 1, userId);
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ad3ad508..ce44dab8 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1343,15 +1343,38 @@
     }
 
     /**
+     * Returns whether the drawn window states of this {@link AppWindowToken} has considered every
+     * child {@link WindowState}. A child is considered if it has been passed into
+     * {@link #updateDrawnWindowStates(WindowState)} after being added. This is used to determine
+     * whether states, such as {@code allDrawn}, can be set, which relies on state variables such as
+     * {@code mNumInterestingWindows}, which depend on all {@link WindowState}s being considered.
+     *
+     * @return {@code true} If all children have been considered, {@code false}.
+     */
+    private boolean allDrawnStatesConsidered() {
+        for (WindowState child : mChildren) {
+            if (!child.getDrawnStatedEvaluated()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
      *  Determines if the token has finished drawing. This should only be called from
      *  {@link DisplayContent#applySurfaceChangesTransaction}
      */
     void updateAllDrawn() {
         if (!allDrawn) {
             // Number of drawn windows can be less when a window is being relaunched, wait for
-            // all windows to be launched and drawn for this token be considered all drawn
+            // all windows to be launched and drawn for this token be considered all drawn.
             final int numInteresting = mNumInterestingWindows;
-            if (numInteresting > 0 && mNumDrawnWindows >= numInteresting && !isRelaunching()) {
+
+            // We must make sure that all present children have been considered (determined by
+            // {@link #allDrawnStatesConsidered}) before evaluating whether everything has been
+            // drawn.
+            if (numInteresting > 0 && allDrawnStatesConsidered()
+                    && mNumDrawnWindows >= numInteresting && !isRelaunching()) {
                 if (DEBUG_VISIBILITY) Slog.v(TAG, "allDrawn: " + this
                         + " interesting=" + numInteresting + " drawn=" + mNumDrawnWindows);
                 allDrawn = true;
@@ -1396,6 +1419,8 @@
      *         windows in this app token where not considered drawn as of the last pass.
      */
     boolean updateDrawnWindowStates(WindowState w) {
+        w.setDrawnStateEvaluated(true /*evaluated*/);
+
         if (DEBUG_STARTING_WINDOW_VERBOSE && w == startingWindow) {
             Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen=" + w.isOnScreen()
                     + " allDrawn=" + allDrawn + " freezingScreen=" + mAppAnimator.freezingScreen);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 9fe7381..05f4626 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1073,7 +1073,7 @@
             }
             if (w.mHasSurface && !rotateSeamlessly) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Set mOrientationChanging of " + w);
-                w.mOrientationChanging = true;
+                w.setOrientationChanging(true);
                 mService.mRoot.mOrientationChangeComplete = false;
                 w.mLastFreezeDuration = 0;
             }
@@ -2679,10 +2679,10 @@
         mService.mWindowsFreezingScreen = WINDOWS_FREEZING_SCREENS_TIMEOUT;
 
         forAllWindows(w -> {
-            if (!w.mOrientationChanging) {
+            if (!w.getOrientationChanging()) {
                 return;
             }
-            w.mOrientationChanging = false;
+            w.setOrientationChanging(false);
             w.mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
                     - mService.mDisplayFreezeTime);
             Slog.w(TAG_WM, "Force clearing orientation change: " + w);
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index bf8fabd..b8b9b9a 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -18,6 +18,9 @@
 
 import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
 
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManager.StackId;
@@ -29,6 +32,7 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.util.ArraySet;
+import android.util.Slog;
 import android.view.DisplayListCanvas;
 import android.view.RenderNode;
 import android.view.ThreadedRenderer;
@@ -57,6 +61,7 @@
  * To access this class, acquire the global window manager lock.
  */
 class TaskSnapshotController {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskSnapshotController" : TAG_WM;
 
     /**
      * Return value for {@link #getSnapshotMode}: We are allowed to take a real screenshot to be
@@ -147,10 +152,17 @@
                     break;
             }
             if (snapshot != null) {
-                mCache.putSnapshot(task, snapshot);
-                mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
-                if (task.getController() != null) {
-                    task.getController().reportSnapshotChanged(snapshot);
+                final GraphicBuffer buffer = snapshot.getSnapshot();
+                if (buffer.getWidth() == 0 || buffer.getHeight() == 0) {
+                    buffer.destroy();
+                    Slog.e(TAG, "Invalid task snapshot dimensions " + buffer.getWidth() + "x"
+                            + buffer.getHeight());
+                } else {
+                    mCache.putSnapshot(task, snapshot);
+                    mPersister.persistSnapshot(task.mTaskId, task.mUserId, snapshot);
+                    if (task.getController() != null) {
+                        task.getController().reportSnapshotChanged(snapshot);
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index b628869..f90b3fb 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -291,7 +291,6 @@
                 failed = true;
             }
             if (!writeBuffer()) {
-                writeBuffer();
                 failed = true;
             }
             if (failed) {
@@ -327,11 +326,7 @@
             final File reducedFile = getReducedResolutionBitmapFile(mTaskId, mUserId);
             final Bitmap bitmap = Bitmap.createHardwareBitmap(mSnapshot.getSnapshot());
             if (bitmap == null) {
-                Slog.e(TAG, "Invalid task snapshot");
-                return false;
-            } else if (bitmap.getWidth() == 0 || bitmap.getHeight() == 0) {
-                Slog.e(TAG, "Invalid task snapshot dimensions " + bitmap.getWidth() + "x"
-                        + bitmap.getHeight());
+                Slog.e(TAG, "Invalid task snapshot hw bitmap");
                 return false;
             }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index ebfeac3..1b4c34d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5789,7 +5789,7 @@
         // orientation.
         if (!okToDisplay() && mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Changing surface while display frozen: " + w);
-            w.mOrientationChanging = true;
+            w.setOrientationChanging(true);
             w.mLastFreezeDuration = 0;
             mRoot.mOrientationChangeComplete = false;
             if (mWindowsFreezingScreen == WINDOWS_FREEZING_SCREENS_NONE) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 5d32443..b403914 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -441,7 +441,7 @@
      * Set when the orientation is changing and this window has not yet
      * been updated for the new orientation.
      */
-    boolean mOrientationChanging;
+    private boolean mOrientationChanging;
 
     /**
      * The orientation during the last visible call to relayout. If our
@@ -560,6 +560,13 @@
     final Rect mLastSurfaceInsets = new Rect();
 
     /**
+     * A flag set by the {@link WindowState} parent to indicate that the parent has examined this
+     * {@link WindowState} in its overall drawing context. This book-keeping allows the parent to
+     * make sure all children have been considered.
+     */
+    private boolean mDrawnStateEvaluated;
+
+    /**
      * Compares two window sub-layers and returns -1 if the first is lesser than the second in terms
      * of z-order and 1 otherwise.
      */
@@ -675,6 +682,27 @@
         mSession.windowAddedLocked(mAttrs.packageName);
     }
 
+    /**
+     * Returns whether this {@link WindowState} has been considered for drawing by its parent.
+     */
+    boolean getDrawnStatedEvaluated() {
+        return mDrawnStateEvaluated;
+    }
+
+    /**
+     * Sets whether this {@link WindowState} has been considered for drawing by its parent. Should
+     * be cleared when detached from parent.
+     */
+    void setDrawnStateEvaluated(boolean evaluated) {
+        mDrawnStateEvaluated = evaluated;
+    }
+
+    @Override
+    void onParentSet() {
+        super.onParentSet();
+        setDrawnStateEvaluated(false /*evaluated*/);
+    }
+
     @Override
     public int getOwningUid() {
         return mOwnerUid;
@@ -1156,7 +1184,8 @@
             // then we need to hold off on unfreezing the display until this window has been
             // redrawn; to do that, we need to go through the process of getting informed by the
             // application when it has finished drawing.
-            if (mOrientationChanging || dragResizingChanged || isResizedWhileNotDragResizing()) {
+            if (getOrientationChanging() || dragResizingChanged
+                    || isResizedWhileNotDragResizing()) {
                 if (DEBUG_SURFACE_TRACE || DEBUG_ANIM || DEBUG_ORIENTATION || DEBUG_RESIZE) {
                     Slog.v(TAG_WM, "Orientation or resize start waiting for draw"
                             + ", mDrawState=DRAW_PENDING in " + this
@@ -1171,17 +1200,33 @@
                 if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG_WM, "Resizing window " + this);
                 mService.mResizingWindows.add(this);
             }
-        } else if (mOrientationChanging) {
+        } else if (getOrientationChanging()) {
             if (isDrawnLw()) {
                 if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Orientation not waiting for draw in "
                         + this + ", surfaceController " + winAnimator.mSurfaceController);
-                mOrientationChanging = false;
+                setOrientationChanging(false);
                 mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
                         - mService.mDisplayFreezeTime);
             }
         }
     }
 
+    boolean getOrientationChanging() {
+        // In addition to the local state flag, we must also consider the difference in the last
+        // reported configuration vs. the current state. If the client code has not been informed of
+        // the change, logic dependent on having finished processing the orientation, such as
+        // unfreezing, could be improperly triggered.
+        // TODO(b/62846907): Checking against {@link mLastReportedConfiguration} could be flaky as
+        //                   this is not necessarily what the client has processed yet. Find a
+        //                   better indicator consistent with the client.
+        return mOrientationChanging
+                || getConfiguration().orientation != mLastReportedConfiguration.orientation;
+    }
+
+    void setOrientationChanging(boolean changing) {
+        mOrientationChanging = changing;
+    }
+
     DisplayContent getDisplayContent() {
         return mToken.getDisplayContent();
     }
@@ -2635,10 +2680,10 @@
 
         mAppFreezing = false;
 
-        if (mHasSurface && !mOrientationChanging
+        if (mHasSurface && !getOrientationChanging()
                 && mService.mWindowsFreezingScreen != WINDOWS_FREEZING_SCREENS_TIMEOUT) {
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "set mOrientationChanging of " + this);
-            mOrientationChanging = true;
+            setOrientationChanging(true);
             mService.mRoot.mOrientationChangeComplete = false;
         }
         mLastFreezeDuration = 0;
@@ -3057,7 +3102,7 @@
             mWinAnimator.mSurfaceResized = false;
             mReportOrientationChanged = false;
         } catch (RemoteException e) {
-            mOrientationChanging = false;
+            setOrientationChanging(false);
             mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
                     - mService.mDisplayFreezeTime);
             // We are assuming the hosting process is dead or in a zombie state.
@@ -3416,10 +3461,13 @@
                     pw.print(" mDestroying="); pw.print(mDestroying);
                     pw.print(" mRemoved="); pw.println(mRemoved);
         }
-        if (mOrientationChanging || mAppFreezing || mTurnOnScreen
+        if (getOrientationChanging() || mAppFreezing || mTurnOnScreen
                 || mReportOrientationChanged) {
             pw.print(prefix); pw.print("mOrientationChanging=");
                     pw.print(mOrientationChanging);
+                    pw.print(" configOrientationChanging=");
+                    pw.print(mLastReportedConfiguration.orientation
+                            != getConfiguration().orientation);
                     pw.print(" mAppFreezing="); pw.print(mAppFreezing);
                     pw.print(" mTurnOnScreen="); pw.print(mTurnOnScreen);
                     pw.print(" mReportOrientationChanged="); pw.println(mReportOrientationChanged);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index cd55156..8f1065f 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1527,11 +1527,11 @@
 
             // There is no need to wait for an animation change if our window is gone for layout
             // already as we'll never be visible.
-            if (w.mOrientationChanging && w.isGoneForLayoutLw()) {
+            if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
                 if (DEBUG_ORIENTATION) {
                     Slog.v(TAG, "Orientation change skips hidden " + w);
                 }
-                w.mOrientationChanging = false;
+                w.setOrientationChanging(false);
             }
             return;
         }
@@ -1564,8 +1564,8 @@
             // really hidden (gone for layout), there is no point in still waiting for it.
             // Note that this does introduce a potential glitch if the window becomes unhidden
             // before it has drawn for the new orientation.
-            if (w.mOrientationChanging && w.isGoneForLayoutLw()) {
-                w.mOrientationChanging = false;
+            if (w.getOrientationChanging() && w.isGoneForLayoutLw()) {
+                w.setOrientationChanging(false);
                 if (DEBUG_ORIENTATION) Slog.v(TAG,
                         "Orientation change skips hidden " + w);
             }
@@ -1618,7 +1618,7 @@
                     mAnimator.setPendingLayoutChanges(w.getDisplayId(),
                             WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM);
                 } else {
-                    w.mOrientationChanging = false;
+                    w.setOrientationChanging(false);
                 }
             }
             if (hasSurface()) {
@@ -1631,14 +1631,14 @@
             displayed = true;
         }
 
-        if (w.mOrientationChanging) {
+        if (w.getOrientationChanging()) {
             if (!w.isDrawnLw()) {
                 mAnimator.mBulkUpdateParams &= ~SET_ORIENTATION_CHANGE_COMPLETE;
                 mAnimator.mLastWindowFreezeSource = w;
                 if (DEBUG_ORIENTATION) Slog.v(TAG,
                         "Orientation continue waiting for draw in " + w);
             } else {
-                w.mOrientationChanging = false;
+                w.setOrientationChanging(false);
                 if (DEBUG_ORIENTATION) Slog.v(TAG, "Orientation change complete in " + w);
             }
         }
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 42272fd..b0fefc4 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -693,8 +693,9 @@
                 // Set the new USB configuration.
                 setUsbConfig(oemFunctions);
 
-                if (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
-                        || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP)) {
+                if (mBootCompleted
+                        && (UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_MTP)
+                        || UsbManager.containsFunction(functions, UsbManager.USB_FUNCTION_PTP))) {
                     // Start up dependent services.
                     updateUsbStateBroadcastIfNeeded(true);
                 }
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index e6b567e..dcf5c27 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -83,6 +83,13 @@
      */
     public static final String REASON_WIFI_ON_BUT_WFC_OFF = "REASON_WIFI_ON_BUT_WFC_OFF";
 
+    /**
+     * Reason code (returned via {@link #getReason()}), which indicates that the video telephony
+     * call was disconnected because IMS access is blocked.
+     * @hide
+     */
+    public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
+
     private int mDisconnectCode;
     private CharSequence mDisconnectLabel;
     private CharSequence mDisconnectDescription;
diff --git a/tests/net/java/com/android/server/connectivity/TetheringTest.java b/tests/net/java/com/android/server/connectivity/TetheringTest.java
index ab874ce..acf9e8f7 100644
--- a/tests/net/java/com/android/server/connectivity/TetheringTest.java
+++ b/tests/net/java/com/android/server/connectivity/TetheringTest.java
@@ -16,6 +16,11 @@
 
 package com.android.server.connectivity;
 
+import static android.hardware.usb.UsbManager.USB_CONFIGURED;
+import static android.hardware.usb.UsbManager.USB_CONNECTED;
+import static android.hardware.usb.UsbManager.USB_FUNCTION_RNDIS;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
+import static android.net.ConnectivityManager.TETHERING_USB;
 import static android.net.wifi.WifiManager.IFACE_IP_MODE_LOCAL_ONLY;
 import static android.net.wifi.WifiManager.IFACE_IP_MODE_TETHERED;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME;
@@ -133,6 +138,7 @@
         public Object getSystemService(String name) {
             if (Context.CONNECTIVITY_SERVICE.equals(name)) return mConnectivityManager;
             if (Context.WIFI_SERVICE.equals(name)) return mWifiManager;
+            if (Context.USB_SERVICE.equals(name)) return mUsbManager;
             return super.getSystemService(name);
         }
     }
@@ -145,7 +151,7 @@
         when(mResources.getStringArray(com.android.internal.R.array.config_tether_usb_regexs))
                 .thenReturn(new String[0]);
         when(mResources.getStringArray(com.android.internal.R.array.config_tether_wifi_regexs))
-                .thenReturn(new String[]{ "test_wlan\\d" });
+                .thenReturn(new String[]{ "test_wlan\\d", "test_rndis\\d" });
         when(mResources.getStringArray(com.android.internal.R.array.config_tether_bluetooth_regexs))
                 .thenReturn(new String[0]);
         when(mResources.getIntArray(com.android.internal.R.array.config_tether_upstream_types))
@@ -245,6 +251,14 @@
         mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
     }
 
+    private void sendUsbBroadcast(boolean connected, boolean configured, boolean rndisFunction) {
+        final Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
+        intent.putExtra(USB_CONNECTED, connected);
+        intent.putExtra(USB_CONFIGURED, configured);
+        intent.putExtra(USB_FUNCTION_RNDIS, rndisFunction);
+        mServiceContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
     private void verifyInterfaceServingModeStarted() throws Exception {
         verify(mNMService, times(1)).getInterfaceConfig(mTestIfname);
         verify(mNMService, times(1))
@@ -287,6 +301,32 @@
     }
 
     @Test
+    public void testUsbConfiguredBroadcastStartsTethering() throws Exception {
+        when(mConnectivityManager.isTetheringSupported()).thenReturn(true);
+
+        // Emulate pressing the USB tethering button in Settings UI.
+        mTethering.startTethering(TETHERING_USB, null, false);
+        mLooper.dispatchAll();
+        verify(mUsbManager, times(1)).setCurrentFunction(UsbManager.USB_FUNCTION_RNDIS, false);
+
+        // Pretend we receive a USB connected broadcast. Here we also pretend
+        // that the RNDIS function is somehow enabled, so that we see if we
+        // might trip ourselves up.
+        sendUsbBroadcast(true, false, true);
+        mLooper.dispatchAll();
+        // This should produce no activity of any kind.
+        verifyNoMoreInteractions(mConnectivityManager);
+        verifyNoMoreInteractions(mNMService);
+
+        // Pretend we then receive USB configured broadcast.
+        sendUsbBroadcast(true, true, true);
+        mLooper.dispatchAll();
+        // Now we should see the start of tethering mechanics (in this case:
+        // tetherMatchingInterfaces() which starts by fetching all interfaces).
+        verify(mNMService, times(1)).listInterfaces();
+    }
+
+    @Test
     public void failingLocalOnlyHotspotLegacyApBroadcastWithIfaceStatusChanged() throws Exception {
         failingLocalOnlyHotspotLegacyApBroadcast(true);
     }
@@ -366,7 +406,7 @@
         when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
+        mTethering.startTethering(TETHERING_WIFI, null, false);
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startSoftAp(null);
         verifyNoMoreInteractions(mWifiManager);
@@ -394,7 +434,7 @@
         when(mWifiManager.startSoftAp(any(WifiConfiguration.class))).thenReturn(true);
 
         // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
+        mTethering.startTethering(TETHERING_WIFI, null, false);
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startSoftAp(null);
         verifyNoMoreInteractions(mWifiManager);
@@ -440,7 +480,7 @@
         /////
 
         // Emulate pressing the WiFi tethering button.
-        mTethering.stopTethering(ConnectivityManager.TETHERING_WIFI);
+        mTethering.stopTethering(TETHERING_WIFI);
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).stopSoftAp();
         verifyNoMoreInteractions(mWifiManager);
@@ -476,7 +516,7 @@
         doThrow(new RemoteException()).when(mNMService).setIpForwardingEnabled(true);
 
         // Emulate pressing the WiFi tethering button.
-        mTethering.startTethering(ConnectivityManager.TETHERING_WIFI, null, false);
+        mTethering.startTethering(TETHERING_WIFI, null, false);
         mLooper.dispatchAll();
         verify(mWifiManager, times(1)).startSoftAp(null);
         verifyNoMoreInteractions(mWifiManager);