Merge "Rename API to match StorageStats." into oc-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index f32f23dd..161fef4 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -41027,7 +41027,6 @@
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
-    method public java.lang.String[] getNamesForUids(int[]);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -49062,6 +49061,7 @@
     method public int getProgress();
     method public boolean getRendererPriorityWaivedWhenNotVisible();
     method public int getRendererRequestedPriority();
+    method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public android.view.textclassifier.TextClassifier getTextClassifier();
diff --git a/api/system-current.txt b/api/system-current.txt
index 97e1f4a..92bc7b0 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -263,6 +263,7 @@
     field public static final java.lang.String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
     field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
     field public static final java.lang.String UPDATE_LOCK = "android.permission.UPDATE_LOCK";
+    field public static final java.lang.String UPDATE_TIME_ZONE_RULES = "android.permission.UPDATE_TIME_ZONE_RULES";
     field public static final java.lang.String USER_ACTIVITY = "android.permission.USER_ACTIVITY";
     field public static final java.lang.String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
     field public static final java.lang.String USE_SIP = "android.permission.USE_SIP";
@@ -11365,6 +11366,8 @@
     method public abstract void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public abstract boolean hasSystemFeature(java.lang.String);
     method public abstract boolean hasSystemFeature(java.lang.String, int);
+    method public abstract int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract boolean isInstantApp();
     method public abstract boolean isInstantApp(java.lang.String);
     method public abstract boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
@@ -44699,7 +44702,6 @@
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
-    method public java.lang.String[] getNamesForUids(int[]);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -44730,6 +44732,8 @@
     method public void grantRuntimePermission(java.lang.String, java.lang.String, android.os.UserHandle);
     method public boolean hasSystemFeature(java.lang.String);
     method public boolean hasSystemFeature(java.lang.String, int);
+    method public int installExistingPackage(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public int installExistingPackage(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isInstantApp();
     method public boolean isInstantApp(java.lang.String);
     method public boolean isPermissionRevokedByPolicy(java.lang.String, java.lang.String);
@@ -52844,6 +52848,7 @@
     method public int getProgress();
     method public boolean getRendererPriorityWaivedWhenNotVisible();
     method public int getRendererRequestedPriority();
+    method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public android.view.textclassifier.TextClassifier getTextClassifier();
@@ -52908,7 +52913,6 @@
     method public void zoomBy(float);
     method public boolean zoomIn();
     method public boolean zoomOut();
-    field public static final java.lang.String DATA_REDUCTION_PROXY_SETTING_CHANGED = "android.webkit.DATA_REDUCTION_PROXY_SETTING_CHANGED";
     field public static final int RENDERER_PRIORITY_BOUND = 1; // 0x1
     field public static final int RENDERER_PRIORITY_IMPORTANT = 2; // 0x2
     field public static final int RENDERER_PRIORITY_WAIVED = 0; // 0x0
@@ -53096,6 +53100,7 @@
     method public abstract java.lang.String findAddress(java.lang.String);
     method public abstract void freeMemoryForTests();
     method public abstract java.lang.String getDefaultUserAgent(android.content.Context);
+    method public abstract android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method public abstract void initSafeBrowsing(android.content.Context, android.webkit.ValueCallback<java.lang.Boolean>);
     method public abstract android.net.Uri[] parseFileChooserResult(int, android.content.Intent);
     method public abstract void setSafeBrowsingWhitelist(java.util.List<java.lang.String>, android.webkit.ValueCallback<java.lang.Boolean>);
diff --git a/api/test-current.txt b/api/test-current.txt
index ccdca6a..31f09c4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -41281,7 +41281,6 @@
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
     method public android.content.Intent getLeanbackLaunchIntentForPackage(java.lang.String);
     method public java.lang.String getNameForUid(int);
-    method public java.lang.String[] getNamesForUids(int[]);
     method public int[] getPackageGids(java.lang.String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public int[] getPackageGids(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.pm.PackageInfo getPackageInfo(java.lang.String, int) throws android.content.pm.PackageManager.NameNotFoundException;
@@ -49509,6 +49508,7 @@
     method public int getProgress();
     method public boolean getRendererPriorityWaivedWhenNotVisible();
     method public int getRendererRequestedPriority();
+    method public static android.net.Uri getSafeBrowsingPrivacyPolicyUrl();
     method public deprecated float getScale();
     method public android.webkit.WebSettings getSettings();
     method public android.view.textclassifier.TextClassifier getTextClassifier();
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 42e6147..7aa80d2 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -103,6 +103,18 @@
  * {@link android.app.backup.BackupAgentHelper}.  That class is particularly
  * suited to handling of simple file or {@link android.content.SharedPreferences}
  * backup and restore.
+ * <p>
+ * <b>Threading</b>
+ * <p>
+ * The constructor, as well as {@link #onCreate()} and {@link #onDestroy()} lifecycle callbacks run
+ * on the main thread (UI thread) of the application that implements the BackupAgent.
+ * The data-handling callbacks:
+ * {@link #onBackup(ParcelFileDescriptor, BackupDataOutput, ParcelFileDescriptor) onBackup()},
+ * {@link #onFullBackup(FullBackupDataOutput)},
+ * {@link #onRestore(BackupDataInput, int, ParcelFileDescriptor) onRestore()},
+ * {@link #onRestoreFile(ParcelFileDescriptor, long, File, int, long, long) onRestoreFile()},
+ * {@link #onRestoreFinished()}, and {@link #onQuotaExceeded(long, long) onQuotaExceeded()}
+ * run on binder pool threads.
  *
  * @see android.app.backup.BackupManager
  * @see android.app.backup.BackupAgentHelper
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index adc6467..449b4a9 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -47,6 +47,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.net.wifi.WifiManager;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
@@ -2314,7 +2315,9 @@
 
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
-     * {@link #hasSystemFeature}: The device supports Wi-Fi Passpoint.
+     * {@link #hasSystemFeature}: The device supports Wi-Fi Passpoint and all
+     * Passpoint related APIs in {@link WifiManager} are supported. Refer to
+     * {@link WifiManager#addOrUpdatePasspointConfiguration} for more info.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_WIFI_PASSPOINT = "android.hardware.wifi.passpoint";
@@ -4718,6 +4721,7 @@
      * on the system for other users, also install it for the calling user.
      * @hide
      */
+    @SystemApi
     public abstract int installExistingPackage(String packageName) throws NameNotFoundException;
 
     /**
@@ -4725,6 +4729,7 @@
      * on the system for other users, also install it for the calling user.
      * @hide
      */
+    @SystemApi
     public abstract int installExistingPackage(String packageName, @InstallReason int installReason)
             throws NameNotFoundException;
 
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
index e48bce1..135d92b 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceState.java
@@ -76,6 +76,7 @@
         void onBusy();
         void onCaptureStarted(RequestHolder holder, long timestamp);
         void onCaptureResult(CameraMetadataNative result, RequestHolder holder);
+        void onRequestQueueEmpty();
         void onRepeatingRequestError(long lastFrameNumber);
     }
 
@@ -218,6 +219,20 @@
     }
 
     /**
+     * Indicate that request queue (non-repeating) becomes empty.
+     *
+     * <p> Send notification that all non-repeating requests have been sent to camera device. </p>
+     */
+    public synchronized void setRequestQueueEmpty() {
+        mCurrentHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mCurrentListener.onRequestQueueEmpty();
+            }
+        });
+    }
+
+    /**
      * Set the listener for state transition callbacks.
      *
      * @param handler handler on which to call the callbacks.
diff --git a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
index f87d8c1..d8df9a0 100644
--- a/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
+++ b/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
@@ -504,12 +504,18 @@
         if (mLegacyDevice.isClosed()) {
             String err = "Cannot end configure, device has been closed.";
             Log.e(TAG, err);
+            synchronized(mConfigureLock) {
+                mConfiguring = false;
+            }
             throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         if (operatingMode != ICameraDeviceUser.NORMAL_MODE) {
             String err = "LEGACY devices do not support this operating mode";
             Log.e(TAG, err);
+            synchronized(mConfigureLock) {
+                mConfiguring = false;
+            }
             throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
         }
 
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 1a05904..621ea84 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -223,6 +223,25 @@
         }
 
         @Override
+        public void onRequestQueueEmpty() {
+            mResultHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    if (DEBUG) {
+                        Log.d(TAG, "doing onRequestQueueEmpty callback");
+                    }
+                    try {
+                        mDeviceCallbacks.onRequestQueueEmpty();
+                    } catch (RemoteException e) {
+                        throw new IllegalStateException(
+                                "Received remote exception during onRequestQueueEmpty callback: ",
+                                e);
+                    }
+                }
+            });
+        }
+
+        @Override
         public void onCaptureResult(final CameraMetadataNative result, final RequestHolder holder) {
             final CaptureResultExtras extras = getExtrasFromRequest(holder);
 
diff --git a/core/java/android/hardware/camera2/legacy/RequestQueue.java b/core/java/android/hardware/camera2/legacy/RequestQueue.java
index 8f252a1..407e5e6 100644
--- a/core/java/android/hardware/camera2/legacy/RequestQueue.java
+++ b/core/java/android/hardware/camera2/legacy/RequestQueue.java
@@ -18,7 +18,6 @@
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.utils.SubmitInfo;
 import android.util.Log;
-import android.util.Pair;
 
 import java.util.ArrayDeque;
 import java.util.List;
@@ -41,6 +40,28 @@
     private int mCurrentRequestId = 0;
     private final List<Long> mJpegSurfaceIds;
 
+    public final class RequestQueueEntry {
+        private final BurstHolder mBurstHolder;
+        private final Long mFrameNumber;
+        private final boolean mQueueEmpty;
+
+        public BurstHolder getBurstHolder() {
+            return mBurstHolder;
+        }
+        public Long getFrameNumber() {
+            return mFrameNumber;
+        }
+        public boolean isQueueEmpty() {
+            return mQueueEmpty;
+        }
+
+        public RequestQueueEntry(BurstHolder burstHolder, Long frameNumber, boolean queueEmpty) {
+            mBurstHolder = burstHolder;
+            mFrameNumber = frameNumber;
+            mQueueEmpty = queueEmpty;
+        }
+    }
+
     public RequestQueue(List<Long> jpegSurfaceIds) {
         mJpegSurfaceIds = jpegSurfaceIds;
     }
@@ -50,10 +71,12 @@
      *
      * <p>If a repeating burst is returned, it will not be removed.</p>
      *
-     * @return a pair containing the next burst and the current frame number, or null if none exist.
+     * @return an entry containing the next burst, the current frame number, and flag about whether
+     * request queue becomes empty. Null if no burst exists.
      */
-    public synchronized Pair<BurstHolder, Long> getNext() {
+    public synchronized RequestQueueEntry getNext() {
         BurstHolder next = mRequestQueue.poll();
+        boolean queueEmptied = (next != null && mRequestQueue.size() == 0);
         if (next == null && mRepeatingRequest != null) {
             next = mRepeatingRequest;
             mCurrentRepeatingFrameNumber = mCurrentFrameNumber +
@@ -64,7 +87,7 @@
             return null;
         }
 
-        Pair<BurstHolder, Long> ret =  new Pair<BurstHolder, Long>(next, mCurrentFrameNumber);
+        RequestQueueEntry ret =  new RequestQueueEntry(next, mCurrentFrameNumber, queueEmptied);
         mCurrentFrameNumber += next.getNumberOfRequests();
         return ret;
     }
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index da62f54..565a43e 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -504,6 +504,15 @@
             previews.add(new Pair<>(p, previewSizeIter.next()));
         }
         mGLThreadManager.setConfigurationAndWait(previews, mCaptureCollector);
+
+        for (Surface p : mPreviewOutputs) {
+            try {
+                LegacyCameraDevice.setSurfaceOrientation(p, facing, orientation);
+            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+                Log.e(TAG, "Surface abandoned, skipping setSurfaceOrientation()", e);
+            }
+        }
+
         mGLThreadManager.allowNewFrames();
         mPreviewTexture = mGLThreadManager.getCurrentSurfaceTexture();
         if (mPreviewTexture != null) {
@@ -713,7 +722,7 @@
                     boolean anyRequestOutputAbandoned = false;
 
                     // Get the next burst from the request queue.
-                    Pair<BurstHolder, Long> nextBurst = mRequestQueue.getNext();
+                    RequestQueue.RequestQueueEntry nextBurst = mRequestQueue.getNext();
 
                     if (nextBurst == null) {
                         // If there are no further requests queued, wait for any currently executing
@@ -748,11 +757,17 @@
                     if (nextBurst != null) {
                         // Queue another capture if we did not get the last burst.
                         handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
+
+                        // Check whether capture queue becomes empty
+                        if (nextBurst.isQueueEmpty()) {
+                            mDeviceState.setRequestQueueEmpty();
+                        }
                     }
 
                     // Complete each request in the burst
+                    BurstHolder burstHolder = nextBurst.getBurstHolder();
                     List<RequestHolder> requests =
-                            nextBurst.first.produceRequestHolders(nextBurst.second);
+                            burstHolder.produceRequestHolders(nextBurst.getFrameNumber());
                     for (RequestHolder holder : requests) {
                         CaptureRequest request = holder.getRequest();
 
@@ -918,8 +933,8 @@
                     }
 
                     // Stop the repeating request if any of its output surfaces is abandoned.
-                    if (anyRequestOutputAbandoned && nextBurst.first.isRepeating()) {
-                        long lastFrameNumber = cancelRepeating(nextBurst.first.getRequestId());
+                    if (anyRequestOutputAbandoned && burstHolder.isRepeating()) {
+                        long lastFrameNumber = cancelRepeating(burstHolder.getRequestId());
                         if (DEBUG) {
                             Log.d(TAG, "Stopped repeating request. Last frame number is " +
                                     lastFrameNumber);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeProvider.java b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
index 722b659..73733a0 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeProvider.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeProvider.java
@@ -76,7 +76,7 @@
 
     /**
      * Returns an {@link AccessibilityNodeInfo} representing a virtual view,
-     * i.e. a descendant of the host View, with the given <code>virtualViewId</code>
+     * such as a descendant of the host View, with the given <code>virtualViewId</code>
      * or the host View itself if <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}.
      * <p>
      * A virtual descendant is an imaginary View that is reported as a part of the view
@@ -123,7 +123,7 @@
     }
 
     /**
-     * Performs an accessibility action on a virtual view, i.e. a descendant of the
+     * Performs an accessibility action on a virtual view, such as a descendant of the
      * host View, with the given <code>virtualViewId</code> or the host View itself
      * if <code>virtualViewId</code> equals to {@link #HOST_VIEW_ID}.
      *
@@ -160,7 +160,7 @@
     }
 
     /**
-     * Find the virtual view, i.e. a descendant of the host View, that has the
+     * Find the virtual view, such as a descendant of the host View, that has the
      * specified focus type.
      *
      * @param focus The focus to find. One of
diff --git a/core/java/android/webkit/SafeBrowsingResponse.java b/core/java/android/webkit/SafeBrowsingResponse.java
index 2ccd2ba..0d0f1cc 100644
--- a/core/java/android/webkit/SafeBrowsingResponse.java
+++ b/core/java/android/webkit/SafeBrowsingResponse.java
@@ -21,6 +21,11 @@
  * created by the WebView and passed to {@link android.webkit.WebViewClient#onSafeBrowsingHit}. The
  * host application must call {@link #showInterstitial(boolean)}, {@link #proceed(boolean)}, or
  * {@link #backToSafety(boolean)} to set the WebView's response to the Safe Browsing hit.
+ *
+ * <p>
+ * If reporting is enabled, all reports will be sent according to the privacy policy referenced by
+ * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}.
+ * </p>
  */
 public abstract class SafeBrowsingResponse {
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index dd716eb..650c7d9 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -347,16 +347,6 @@
         implements ViewTreeObserver.OnGlobalFocusChangeListener,
         ViewGroup.OnHierarchyChangeListener, ViewDebug.HierarchyHandler {
 
-    /**
-     * Broadcast Action: Indicates the data reduction proxy setting changed.
-     * Sent by the settings app when user changes the data reduction proxy value. This intent will
-     * always stay as a hidden API.
-     * @hide
-     */
-    @SystemApi
-    public static final String DATA_REDUCTION_PROXY_SETTING_CHANGED =
-            "android.webkit.DATA_REDUCTION_PROXY_SETTING_CHANGED";
-
     private static final String LOGTAG = "WebView";
 
     // Throwing an exception for incorrect thread usage if the
@@ -1700,6 +1690,16 @@
     }
 
     /**
+     * Returns a URL pointing to the privacy policy for Safe Browsing reporting.
+     *
+     * @return the url pointing to a privacy policy document which can be displayed to users.
+     */
+    @NonNull
+    public static Uri getSafeBrowsingPrivacyPolicyUrl() {
+        return getFactory().getStatics().getSafeBrowsingPrivacyPolicyUrl();
+    }
+
+    /**
      * Gets the WebBackForwardList for this WebView. This contains the
      * back/forward list for use in querying each item in the history stack.
      * This is a copy of the private WebBackForwardList so it contains only a
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 613eb72..4f6513f 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -16,6 +16,7 @@
 
 package android.webkit;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.Context;
 import android.content.Intent;
@@ -95,6 +96,13 @@
         * ValueCallback<Boolean>)}
         */
         void setSafeBrowsingWhitelist(List<String> urls, ValueCallback<Boolean> callback);
+
+        /**
+         * Implement the API method
+         * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}
+         */
+        @NonNull
+        Uri getSafeBrowsingPrivacyPolicyUrl();
     }
 
     Statics getStatics();
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index b55ad21..5b0f8d5 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2261,7 +2261,7 @@
          <p>An application requesting this permission is responsible for
          verifying the source and integrity of the update before passing
          it off to the installer components.
-         @hide -->
+         @SystemApi @hide -->
     <permission android:name="android.permission.UPDATE_TIME_ZONE_RULES"
         android:protectionLevel="signature|privileged" />
 
diff --git a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
index 29b6fd0..c707240 100644
--- a/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
+++ b/core/tests/BroadcastRadioTests/src/android/hardware/radio/tests/functional/RadioTunerTest.java
@@ -131,7 +131,9 @@
 
         // find FM band and build its config
         mModule = mModules.get(0);
+
         for (RadioManager.BandDescriptor band : mModule.getBands()) {
+            Log.d(TAG, "Band: " + band);
             int bandType = band.getType();
             if (bandType == RadioManager.BAND_AM || bandType == RadioManager.BAND_AM_HD) {
                 mAmBandDescriptor = (RadioManager.AmBandDescriptor)band;
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index dbbbfc6..26e65dd 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -57,10 +57,10 @@
  * SoundPool will automatically stop a previously playing stream based first
  * on priority and then by age within that priority. Limiting the maximum
  * number of streams helps to cap CPU loading and reducing the likelihood that
- * audio mixing will impact visuals or UI performance.</p> 
+ * audio mixing will impact visuals or UI performance.</p>
  *
  * <p>Sounds can be looped by setting a non-zero loop value. A value of -1
- * causes the sound to loop forever. In this case, the application must 
+ * causes the sound to loop forever. In this case, the application must
  * explicitly call the stop() function to stop the sound. Any other non-zero
  * value will cause the sound to repeat the specified number of times, e.g.
  * a value of 3 causes the sound to play a total of 4 times.</p>
@@ -101,7 +101,7 @@
  * <p>Note that since streams can be stopped due to resource constraints, the
  * streamID is a reference to a particular instance of a stream. If the stream
  * is stopped to allow a higher priority stream to play, the stream is no
- * longer be valid. However, the application is allowed to call methods on
+ * longer valid. However, the application is allowed to call methods on
  * the streamID without error. This may help simplify program logic since
  * the application need not concern itself with the stream lifecycle.</p>
  *
@@ -137,7 +137,7 @@
      *
      * @param maxStreams the maximum number of simultaneous streams for this
      *                   SoundPool object
-     * @param streamType the audio stream type as described in AudioManager 
+     * @param streamType the audio stream type as described in AudioManager
      *                   For example, game applications will normally use
      *                   {@link AudioManager#STREAM_MUSIC}.
      * @param srcQuality the sample-rate converter quality. Currently has no
@@ -213,7 +213,7 @@
      * "R.raw.explosion" as the resource ID. Note that this means you cannot
      * have both an "explosion.wav" and an "explosion.mp3" in the res/raw
      * directory.
-     * 
+     *
      * @param context the application context
      * @param resId the resource ID
      * @param priority the priority of the sound. Currently has no effect. Use
@@ -287,7 +287,7 @@
     /**
      * Play a sound from a sound ID.
      *
-     * Play the sound specified by the soundID. This is the value 
+     * Play the sound specified by the soundID. This is the value
      * returned by the load() function. Returns a non-zero streamID
      * if successful, zero if it fails. The streamID can be used to
      * further control playback. Note that calling play() may cause
@@ -509,7 +509,7 @@
         }
     }
 
-    private native final int _load(FileDescriptor fd, long offset, long length, int priority); 
+    private native final int _load(FileDescriptor fd, long offset, long length, int priority);
 
     private native final int native_setup(Object weakRef, int maxStreams,
             Object/*AudioAttributes*/ attributes);
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 506c294..89e2675 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -328,9 +328,13 @@
     <integer name="config_showTemperatureWarning">0</integer>
 
     <!-- Temp at which to show a warning notification if config_showTemperatureWarning is true.
-         If < 0, uses the value from HardwarePropertiesManager#getDeviceTemperatures. -->
+         If < 0, uses the value from
+         HardwarePropertiesManager#getDeviceTemperatures - config_warningTemperatureTolerance. -->
     <integer name="config_warningTemperature">-1</integer>
 
+    <!-- Fudge factor for how much below the shutdown temp to show the warning. -->
+    <integer name="config_warningTemperatureTolerance">2</integer>
+
     <!-- Accessibility actions -->
     <item type="id" name="action_split_task_to_left" />
     <item type="id" name="action_split_task_to_right" />
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index d668a41..69ccb67 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -163,7 +163,7 @@
     <string name="usb_debugging_secondary_user_title">USB debugging not allowed</string>
 
     <!-- Message of notification shown when trying to enable USB debugging but a secondary user is the current foreground user. -->
-    <string name="usb_debugging_secondary_user_message">The user currently signed in to this device can\'t turn on USB debugging. To use this feature, please switch to an Admin user.</string>
+    <string name="usb_debugging_secondary_user_message">The user currently signed in to this device can\'t turn on USB debugging. To use this feature, switch to the primary user.</string>
 
     <!-- Checkbox label for application compatibility mode ON (zooming app to look like it's running
          on a phone).  [CHAR LIMIT=25] -->
@@ -1904,7 +1904,7 @@
     <string name="pip_phone_dismiss_hint">Drag down to dismiss</string>
 
     <!-- Title of menu shown over picture-in-picture. Used for accessibility. -->
-    <string name="pip_menu_title">Picture in picture menu</string>
+    <string name="pip_menu_title">Menu</string>
 
     <!-- PiP BTW notification title. [CHAR LIMIT=50] -->
     <string name="pip_notification_title"><xliff:g id="name" example="Google Maps">%s</xliff:g> is in picture-in-picture</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 32775fe..669594b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -646,13 +646,6 @@
         return mStrongAuthTracker;
     }
 
-    public void reportSuccessfulStrongAuthUnlockAttempt() {
-        if (mFpm != null) {
-            byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
-            mFpm.resetTimeout(token);
-        }
-    }
-
     private void notifyStrongAuthStateChanged(int userId) {
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index 9c1cb4e..ecc2111 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -39,6 +39,8 @@
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.PluginManagerImpl;
 import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.power.PowerNotificationWarnings;
+import com.android.systemui.power.PowerUI;
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl;
 import com.android.systemui.statusbar.phone.DarkIconDispatcherImpl;
 import com.android.systemui.statusbar.phone.ManagedProfileController;
@@ -296,6 +298,8 @@
         mProviders.put(PluginActivityManager.class,
                 () -> new PluginActivityManager(mContext, getDependency(PluginManager.class)));
 
+        mProviders.put(PowerUI.WarningsUI.class, () -> new PowerNotificationWarnings(mContext));
+
         // Put all dependencies above here so the factory can override them if it wants.
         SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 6777ea2..e3eaadd 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -203,7 +203,7 @@
             return Math.max(1 - progress, 0);
         }
 
-        return Math.min(0, Math.max(1, progress / SWIPE_PROGRESS_FADE_END));
+        return 1f - Math.max(0, Math.min(1, progress / SWIPE_PROGRESS_FADE_END));
     }
 
     private void updateSwipeProgressFromOffset(View animView, boolean dismissable) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 302bc2d..d374d68 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -64,17 +64,13 @@
                 createDozeTriggers(context, sensorManager, host, alarmManager, config, params,
                         handler, wakeLock, machine),
                 createDozeUi(context, host, wakeLock, machine, handler, alarmManager),
-                createDozeScreenState(wrappedService),
+                new DozeScreenState(wrappedService, handler),
                 createDozeScreenBrightness(context, wrappedService, sensorManager, host, handler),
         });
 
         return machine;
     }
 
-    private DozeMachine.Part createDozeScreenState(DozeMachine.Service service) {
-        return new DozeScreenState(service);
-    }
-
     private DozeMachine.Part createDozeScreenBrightness(Context context,
             DozeMachine.Service service, SensorManager sensorManager, DozeHost host,
             Handler handler) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 846ec27..63f5d97 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -16,7 +16,7 @@
 
 package com.android.systemui.doze;
 
-import android.content.Context;
+import android.os.Handler;
 import android.view.Display;
 
 /**
@@ -24,16 +24,46 @@
  */
 public class DozeScreenState implements DozeMachine.Part {
     private final DozeMachine.Service mDozeService;
+    private final Handler mHandler;
+    private int mPendingScreenState = Display.STATE_UNKNOWN;
+    private Runnable mApplyPendingScreenState = this::applyPendingScreenState;
 
-    public DozeScreenState(DozeMachine.Service service) {
+    public DozeScreenState(DozeMachine.Service service, Handler handler) {
         mDozeService = service;
+        mHandler = handler;
     }
 
     @Override
     public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
         int screenState = newState.screenState();
+        if (screenState == Display.STATE_UNKNOWN) {
+            // We'll keep it in the existing state
+            return;
+        }
+        boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
+        if (messagePending || oldState == DozeMachine.State.INITIALIZED) {
+            // During initialization, we hide the navigation bar. That is however only applied after
+            // a traversal; setting the screen state here is immediate however, so it can happen
+            // that the screen turns on again before the navigation bar is hidden. To work around
+            // that, wait for a traversal to happen before applying the initial screen state.
+            mPendingScreenState = screenState;
+            if (!messagePending) {
+                mHandler.post(mApplyPendingScreenState);
+            }
+            return;
+        }
+        applyScreenState(screenState);
+    }
+
+    private void applyPendingScreenState() {
+        applyScreenState(mPendingScreenState);
+        mPendingScreenState = Display.STATE_UNKNOWN;
+    }
+
+    private void applyScreenState(int screenState) {
         if (screenState != Display.STATE_UNKNOWN) {
             mDozeService.setDozeScreenState(screenState);
+            mPendingScreenState = Display.STATE_UNKNOWN;
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d132e76..4733008 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -560,9 +560,6 @@
             }
 
             tryKeyguardDone();
-            if (strongAuth) {
-                mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
-            }
         }
 
         @Override
@@ -591,9 +588,6 @@
             mStatusBarKeyguardViewManager.startPreHideAnimation(mHideAnimationFinishedRunnable);
             mHandler.sendEmptyMessageDelayed(KEYGUARD_DONE_PENDING_TIMEOUT,
                     KEYGUARD_DONE_PENDING_TIMEOUT_MS);
-            if (strongAuth) {
-                mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
-            }
             Trace.endSection();
         }
 
@@ -1288,7 +1282,6 @@
                 // Without this, settings is not enabled until the lock screen first appears
                 setShowingLocked(false);
                 hideLocked();
-                mUpdateMonitor.reportSuccessfulStrongAuthUnlockAttempt();
                 return;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index e76276d..c29b362 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -106,10 +106,9 @@
     private SystemUIDialog mHighTempDialog;
     private SystemUIDialog mThermalShutdownDialog;
 
-    public PowerNotificationWarnings(Context context, NotificationManager notificationManager,
-            StatusBar statusBar) {
+    public PowerNotificationWarnings(Context context) {
         mContext = context;
-        mNoMan = notificationManager;
+        mNoMan = mContext.getSystemService(NotificationManager.class);
         mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
         mReceiver.init();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 28172b7..f378268 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -16,7 +16,6 @@
 
 package com.android.systemui.power;
 
-import android.app.NotificationManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -33,14 +32,17 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
-import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.util.Slog;
+
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.statusbar.phone.StatusBar;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Arrays;
@@ -84,10 +86,7 @@
         mHardwarePropertiesManager = (HardwarePropertiesManager)
                 mContext.getSystemService(Context.HARDWARE_PROPERTIES_SERVICE);
         mScreenOffTime = mPowerManager.isScreenOn() ? -1 : SystemClock.elapsedRealtime();
-        mWarnings = new PowerNotificationWarnings(
-                mContext,
-                (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE),
-                getComponent(StatusBar.class));
+        mWarnings = Dependency.get(WarningsUI.class);
         mLastConfiguration.setTo(mContext.getResources().getConfiguration());
 
         ContentObserver obs = new ContentObserver(mHandler) {
@@ -267,13 +266,14 @@
             // Get the throttling temperature. No need to check if we're not throttling.
             float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
                     HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
-                    HardwarePropertiesManager.TEMPERATURE_THROTTLING);
+                    HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
             if (throttlingTemps == null
                     || throttlingTemps.length == 0
                     || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
                 return;
             }
-            mThresholdTemp = throttlingTemps[0];
+            mThresholdTemp = throttlingTemps[0] -
+                    resources.getInteger(R.integer.config_warningTemperatureTolerance);
         }
 
         setNextLogTime();
@@ -294,7 +294,8 @@
         }
     }
 
-    private void updateTemperatureWarning() {
+    @VisibleForTesting
+    protected void updateTemperatureWarning() {
         float[] temps = mHardwarePropertiesManager.getDeviceTemperatures(
                 HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
                 HardwarePropertiesManager.TEMPERATURE_CURRENT);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 7f5c595..6e631fa 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -134,6 +134,7 @@
     private boolean mShowA11yStream;
 
     private int mActiveStream;
+    private int mPrevActiveStream;
     private boolean mAutomute = VolumePrefs.DEFAULT_ENABLE_AUTOMUTE;
     private boolean mSilentMode = VolumePrefs.DEFAULT_ENABLE_SILENT_MODE;
     private State mState;
@@ -626,10 +627,19 @@
         }
     }
 
-    private boolean shouldBeVisibleH(VolumeRow row, boolean isActive) {
+    private boolean shouldBeVisibleH(VolumeRow row, VolumeRow activeRow) {
+        boolean isActive = row == activeRow;
         if (row.stream == AudioSystem.STREAM_ACCESSIBILITY) {
             return mShowA11yStream;
         }
+
+        // if the active row is accessibility, then continue to display previous
+        // active row since accessibility is dispalyed under it
+        if (activeRow.stream == AudioSystem.STREAM_ACCESSIBILITY &&
+                row.stream == mPrevActiveStream) {
+            return true;
+        }
+
         return mExpanded && row.view.getVisibility() == View.VISIBLE
                 || (mExpanded && (row.important || isActive))
                 || !mExpanded && isActive;
@@ -643,7 +653,7 @@
         // apply changes to all rows
         for (final VolumeRow row : mRows) {
             final boolean isActive = row == activeRow;
-            final boolean shouldBeVisible = shouldBeVisibleH(row, isActive);
+            final boolean shouldBeVisible = shouldBeVisibleH(row, activeRow);
             Util.setVisOrGone(row.view, shouldBeVisible);
             Util.setVisOrGone(row.header, shouldBeVisible);
             if (row.view.isShown()) {
@@ -686,6 +696,7 @@
         }
 
         if (mActiveStream != state.activeStream) {
+            mPrevActiveStream = mActiveStream;
             mActiveStream = state.activeStream;
             updateRowsH(getActiveRow());
             rescheduleTimeoutH();
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index 03f3c56..adb3baf 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -41,6 +41,7 @@
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.TRUST_LISTENER" />
     <uses-permission android:name="android.permission.USE_FINGERPRINT" />
+    <uses-permission android:name="android.permission.DEVICE_POWER" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
index e54c792..c787eff 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeScreenStateTest.java
@@ -24,7 +24,14 @@
 import static com.android.systemui.doze.DozeMachine.State.UNINITIALIZED;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
 
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.view.Display;
@@ -41,11 +48,13 @@
 
     DozeServiceFake mServiceFake;
     DozeScreenState mScreen;
+    private ImmediateHandler mHandler;
 
     @Before
     public void setUp() throws Exception {
         mServiceFake = new DozeServiceFake();
-        mScreen = new DozeScreenState(mServiceFake);
+        mHandler = spy(new ImmediateHandler(Looper.getMainLooper()));
+        mScreen = new DozeScreenState(mServiceFake, mHandler);
     }
 
     @Test
@@ -95,4 +104,28 @@
         assertEquals(Display.STATE_OFF, mServiceFake.screenState);
     }
 
+    @Test
+    public void test_postedToHandler() {
+        mScreen.transitionTo(UNINITIALIZED, INITIALIZED);
+        mScreen.transitionTo(INITIALIZED, DOZE_AOD);
+
+        verify(mHandler).sendMessageAtTime(any(), anyLong());
+    }
+
+    private static class ImmediateHandler extends Handler {
+
+        public ImmediateHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public boolean sendMessageAtTime(Message msg, long uptimeMillis) {
+            Runnable callback = msg.getCallback();
+            if (callback != null) {
+                callback.run();
+                return false;
+            }
+            return super.sendMessageAtTime(msg, uptimeMillis);
+        }
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index ac37d1e..7f07e0c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -52,8 +52,8 @@
     @Before
     public void setUp() throws Exception {
         // Test Instance.
-        mPowerNotificationWarnings = new PowerNotificationWarnings(
-                mContext, mMockNotificationManager, null);
+        mContext.addMockSystemService(NotificationManager.class, mMockNotificationManager);
+        mPowerNotificationWarnings = new PowerNotificationWarnings(mContext);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
new file mode 100644
index 0000000..e4734a4
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.power;
+
+import static android.os.HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN;
+import static android.os.HardwarePropertiesManager.TEMPERATURE_CURRENT;
+import static android.os.HardwarePropertiesManager.TEMPERATURE_SHUTDOWN;
+import static android.provider.Settings.Global.SHOW_TEMPERATURE_WARNING;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.os.HardwarePropertiesManager;
+import android.provider.Settings;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.testing.TestableResources;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.power.PowerUI.WarningsUI;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class PowerUITest extends SysuiTestCase {
+
+    private HardwarePropertiesManager mHardProps;
+    private WarningsUI mMockWarnings;
+    private PowerUI mPowerUI;
+
+    @Before
+    public void setup() {
+        mMockWarnings = mDependency.injectMockDependency(WarningsUI.class);
+        mHardProps = mock(HardwarePropertiesManager.class);
+        mContext.putComponent(StatusBar.class, mock(StatusBar.class));
+        mContext.addMockSystemService(Context.HARDWARE_PROPERTIES_SERVICE, mHardProps);
+
+        createPowerUi();
+    }
+
+    @Test
+    public void testNoConfig_NoWarnings() {
+        setOverThreshold();
+        Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
+        TestableResources resources = mContext.getOrCreateTestableResources();
+        resources.addOverride(R.integer.config_showTemperatureWarning, 0);
+        resources.addOverride(R.integer.config_warningTemperature, 55);
+
+        mPowerUI.start();
+        verify(mMockWarnings, never()).showHighTemperatureWarning();
+    }
+
+    @Test
+    public void testConfig_NoWarnings() {
+        setUnderThreshold();
+        Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
+        TestableResources resources = mContext.getOrCreateTestableResources();
+        resources.addOverride(R.integer.config_showTemperatureWarning, 1);
+        resources.addOverride(R.integer.config_warningTemperature, 55);
+
+        mPowerUI.start();
+        verify(mMockWarnings, never()).showHighTemperatureWarning();
+    }
+
+    @Test
+    public void testConfig_Warnings() {
+        setOverThreshold();
+        Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
+        TestableResources resources = mContext.getOrCreateTestableResources();
+        resources.addOverride(R.integer.config_showTemperatureWarning, 1);
+        resources.addOverride(R.integer.config_warningTemperature, 55);
+
+        mPowerUI.start();
+        verify(mMockWarnings).showHighTemperatureWarning();
+    }
+
+    @Test
+    public void testSettingOverrideConfig() {
+        setOverThreshold();
+        Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 1);
+        TestableResources resources = mContext.getOrCreateTestableResources();
+        resources.addOverride(R.integer.config_showTemperatureWarning, 0);
+        resources.addOverride(R.integer.config_warningTemperature, 55);
+
+        mPowerUI.start();
+        verify(mMockWarnings).showHighTemperatureWarning();
+    }
+
+    @Test
+    public void testShutdownBasedThreshold() {
+        int tolerance = 2;
+        Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
+        TestableResources resources = mContext.getOrCreateTestableResources();
+        resources.addOverride(R.integer.config_showTemperatureWarning, 1);
+        resources.addOverride(R.integer.config_warningTemperature, -1);
+        resources.addOverride(R.integer.config_warningTemperatureTolerance, tolerance);
+        when(mHardProps.getDeviceTemperatures(DEVICE_TEMPERATURE_SKIN, TEMPERATURE_SHUTDOWN))
+                .thenReturn(new float[] { 55 + tolerance });
+
+        setCurrentTemp(54); // Below threshold.
+        mPowerUI.start();
+        verify(mMockWarnings, never()).showHighTemperatureWarning();
+
+        setCurrentTemp(56); // Above threshold.
+        mPowerUI.updateTemperatureWarning();
+        verify(mMockWarnings).showHighTemperatureWarning();
+    }
+
+    private void setCurrentTemp(float temp) {
+        when(mHardProps.getDeviceTemperatures(DEVICE_TEMPERATURE_SKIN, TEMPERATURE_CURRENT))
+                .thenReturn(new float[] { temp });
+    }
+
+    private void setOverThreshold() {
+        setCurrentTemp(50000);
+    }
+
+    private void setUnderThreshold() {
+        setCurrentTemp(5);
+    }
+
+    private void createPowerUi() {
+        mPowerUI = new PowerUI();
+        mPowerUI.mContext = mContext;
+        mPowerUI.mComponents = mContext.getComponents();
+    }
+}
diff --git a/services/core/java/com/android/server/content/SyncLogger.java b/services/core/java/com/android/server/content/SyncLogger.java
index d93bdc9..8503768 100644
--- a/services/core/java/com/android/server/content/SyncLogger.java
+++ b/services/core/java/com/android/server/content/SyncLogger.java
@@ -98,6 +98,13 @@
     }
 
     /**
+     * @return whether log is enabled or not.
+     */
+    public boolean enabled() {
+        return false;
+    }
+
+    /**
      * Actual implementation which is only used on userdebug/eng builds (by default).
      */
     private static class RotatingFileLogger extends SyncLogger {
@@ -134,6 +141,11 @@
             mLogPath = new File(Environment.getDataSystemDirectory(), "syncmanager-log");
         }
 
+        @Override
+        public boolean enabled() {
+            return true;
+        }
+
         private void handleException(String message, Exception e) {
             if (!mErrorShown) {
                 Slog.e(TAG, message, e);
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 3e05d50..f41aa5f 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -58,6 +58,7 @@
 import android.net.NetworkInfo;
 import android.net.TrafficStats;
 import android.os.BatteryStats;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -461,6 +462,7 @@
                             continue;
                         }
                         if (opx.key.equals(opy.key)) {
+                            mLogger.log("Removing duplicate sync: ", opy);
                             mJobScheduler.cancel(opy.jobId);
                         }
                     }
@@ -473,25 +475,57 @@
         if (mJobScheduler != null) {
             return;
         }
-        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-            Log.d(TAG, "initializing JobScheduler object.");
-        }
-        mJobScheduler = (JobScheduler) mContext.getSystemService(
-                Context.JOB_SCHEDULER_SERVICE);
-        mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
-        // Get all persisted syncs from JobScheduler
-        List<JobInfo> pendingJobs = mJobScheduler.getAllPendingJobs();
-        for (JobInfo job : pendingJobs) {
-            SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
-            if (op != null) {
-                if (!op.isPeriodic) {
-                    // Set the pending status of this EndPoint to true. Pending icon is
-                    // shown on the settings activity.
-                    mSyncStorageEngine.markPending(op.target, true);
+        final long token = Binder.clearCallingIdentity();
+        try {
+            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                Log.d(TAG, "initializing JobScheduler object.");
+            }
+            mJobScheduler = (JobScheduler) mContext.getSystemService(
+                    Context.JOB_SCHEDULER_SERVICE);
+            mJobSchedulerInternal = LocalServices.getService(JobSchedulerInternal.class);
+            // Get all persisted syncs from JobScheduler
+            List<JobInfo> pendingJobs = mJobScheduler.getAllPendingJobs();
+
+            int numPersistedPeriodicSyncs = 0;
+            int numPersistedOneshotSyncs = 0;
+            for (JobInfo job : pendingJobs) {
+                SyncOperation op = SyncOperation.maybeCreateFromJobExtras(job.getExtras());
+                if (op != null) {
+                    if (op.isPeriodic) {
+                        numPersistedPeriodicSyncs++;
+                    } else {
+                        numPersistedOneshotSyncs++;
+                        // Set the pending status of this EndPoint to true. Pending icon is
+                        // shown on the settings activity.
+                        mSyncStorageEngine.markPending(op.target, true);
+                    }
                 }
             }
+            if (mLogger.enabled()) {
+                mLogger.log("Connected to JobScheduler: "
+                        + numPersistedPeriodicSyncs + " periodic syncs "
+                        + numPersistedOneshotSyncs + " oneshot syncs.");
+            }
+            cleanupJobs();
+
+            if ((numPersistedPeriodicSyncs == 0) && likelyHasPeriodicSyncs()) {
+                Slog.wtf(TAG, "Device booted with no persisted periodic syncs.");
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
         }
-        cleanupJobs();
+    }
+
+    /**
+     * @return whether the device most likely has some periodic syncs.
+     */
+    private boolean likelyHasPeriodicSyncs() {
+        try {
+            return AccountManager.get(mContext).getAccountsByType("com.google").length > 0;
+        } catch (Throwable th) {
+            // Just in case.
+        }
+        return false;
     }
 
     private JobScheduler getJobScheduler() {
@@ -1085,11 +1119,13 @@
     }
 
     private void removeSyncsForAuthority(EndPoint info) {
+        mLogger.log("removeSyncsForAuthority: ", info);
         verifyJobScheduler();
         List<SyncOperation> ops = getAllPendingSyncs();
         for (SyncOperation op: ops) {
             if (op.target.matchesSpec(info)) {
-                 getJobScheduler().cancel(op.jobId);
+                mLogger.log("canceling: ", op);
+                getJobScheduler().cancel(op.jobId);
             }
         }
     }
@@ -1634,6 +1670,7 @@
     }
 
     private void onUserRemoved(int userId) {
+        mLogger.log("onUserRemoved: u", userId);
         updateRunningAccounts(null /* Don't sync any target */);
 
         // Clean up the storage engine database
@@ -2926,6 +2963,9 @@
                     Slog.v(TAG, acc.toString());
                 }
             }
+            if (mLogger.enabled()) {
+                mLogger.log("updateRunningAccountsH: ", Arrays.toString(mRunningAccounts));
+            }
             if (mBootCompleted) {
                 doDatabaseCleanup();
             }
@@ -2957,6 +2997,7 @@
             List<SyncOperation> ops = getAllPendingSyncs();
             for (SyncOperation op: ops) {
                 if (!containsAccountAndUser(allAccounts, op.target.account, op.target.userId)) {
+                    mLogger.log("canceling: ", op);
                     getJobScheduler().cancel(op.jobId);
                 }
             }
@@ -3075,6 +3116,7 @@
                                 "removePeriodicSyncInternalH");
                         runSyncFinishedOrCanceledH(null, asc);
                     }
+                    mLogger.log("removePeriodicSyncInternalH-canceling: ", op);
                     getJobScheduler().cancel(op.jobId);
                 }
             }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index c6ea72f..c672949 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -561,6 +561,7 @@
         mDeviceProvisionedObserver.onSystemReady();
         // TODO: maybe skip this for split system user mode.
         mStorage.prefetchUser(UserHandle.USER_SYSTEM);
+        mStrongAuth.systemReady();
     }
 
     private void migrateOldData() {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
index 0966153..542b929 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsStrongAuth.java
@@ -27,6 +27,7 @@
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.IStrongAuthTracker;
 import android.content.Context;
+import android.hardware.fingerprint.FingerprintManager;
 import android.os.Binder;
 import android.os.DeadObjectException;
 import android.os.Handler;
@@ -64,6 +65,7 @@
     private final Context mContext;
 
     private AlarmManager mAlarmManager;
+    private FingerprintManager mFingerprintManager;
 
     public LockSettingsStrongAuth(Context context) {
         mContext = context;
@@ -71,6 +73,10 @@
         mAlarmManager = context.getSystemService(AlarmManager.class);
     }
 
+    public void systemReady() {
+        mFingerprintManager = mContext.getSystemService(FingerprintManager.class);
+    }
+
     private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
         for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
             if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
@@ -188,6 +194,11 @@
     }
 
     public void reportSuccessfulStrongAuthUnlock(int userId) {
+        if (mFingerprintManager != null) {
+            byte[] token = null; /* TODO: pass real auth token once fp HAL supports it */
+            mFingerprintManager.resetTimeout(token);
+        }
+
         final int argNotUsed = 0;
         mHandler.obtainMessage(MSG_SCHEDULE_STRONG_AUTH_TIMEOUT, userId, argNotUsed).sendToTarget();
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index c8d8e03..390c45e 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -554,7 +554,7 @@
     {
         final int pid;
         final String pkg;
-        final ITransientNotification callback;
+        ITransientNotification callback;
         int duration;
         Binder token;
 
@@ -571,6 +571,10 @@
             this.duration = duration;
         }
 
+        void update(ITransientNotification callback) {
+            this.callback = callback;
+        }
+
         void dump(PrintWriter pw, String prefix, DumpFilter filter) {
             if (filter != null && !filter.matches(pkg)) return;
             pw.println(prefix + this);
@@ -1604,38 +1608,28 @@
                 long callingId = Binder.clearCallingIdentity();
                 try {
                     ToastRecord record;
-                    int index = indexOfToastLocked(pkg, callback);
-                    // If it's already in the queue, we update it in place, we don't
-                    // move it to the end of the queue.
+                    int index;
+                    // All packages aside from the android package can enqueue one toast at a time
+                    if (!isSystemToast) {
+                        index = indexOfToastPackageLocked(pkg);
+                    } else {
+                        index = indexOfToastLocked(pkg, callback);
+                    }
+
+                    // If the package already has a toast, we update its toast
+                    // in the queue, we don't move it to the end of the queue.
                     if (index >= 0) {
                         record = mToastQueue.get(index);
                         record.update(duration);
+                        record.update(callback);
                     } else {
-                        // Limit the number of toasts that any given package except the android
-                        // package can enqueue.  Prevents DOS attacks and deals with leaks.
-                        if (!isSystemToast) {
-                            int count = 0;
-                            final int N = mToastQueue.size();
-                            for (int i=0; i<N; i++) {
-                                 final ToastRecord r = mToastQueue.get(i);
-                                 if (r.pkg.equals(pkg)) {
-                                     count++;
-                                     if (count >= MAX_PACKAGE_NOTIFICATIONS) {
-                                         Slog.e(TAG, "Package has already posted " + count
-                                                + " toasts. Not showing more. Package=" + pkg);
-                                         return;
-                                     }
-                                 }
-                            }
-                        }
-
                         Binder token = new Binder();
                         mWindowManagerInternal.addWindowToken(token, TYPE_TOAST, DEFAULT_DISPLAY);
                         record = new ToastRecord(callingPid, pkg, callback, duration, token);
                         mToastQueue.add(record);
                         index = mToastQueue.size() - 1;
-                        keepProcessAliveIfNeededLocked(callingPid);
                     }
+                    keepProcessAliveIfNeededLocked(callingPid);
                     // If it's at index 0, it's the current toast.  It doesn't matter if it's
                     // new or just been updated.  Call back and tell it to show itself.
                     // If the callback fails, this will remove it from the list, so don't
@@ -2823,7 +2817,7 @@
         public void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId,
                 boolean granted) throws RemoteException {
             Preconditions.checkNotNull(listener);
-            enforceSystemOrSystemUI("grant notification listener access");
+            checkCallerIsSystemOrShell();
             if (!mActivityManager.isLowRamDevice()) {
                 mConditionProviders.setPackageOrComponentEnabled(listener.flattenToString(),
                         userId, false, granted);
@@ -2844,7 +2838,7 @@
         public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
                 int userId, boolean granted) throws RemoteException {
             Preconditions.checkNotNull(assistant);
-            enforceSystemOrSystemUI("grant notification assistant access");
+            checkCallerIsSystemOrShell();
             if (!mActivityManager.isLowRamDevice()) {
                 mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
                         userId, false, granted);
@@ -4241,7 +4235,21 @@
         int len = list.size();
         for (int i=0; i<len; i++) {
             ToastRecord r = list.get(i);
-            if (r.pkg.equals(pkg) && r.callback.asBinder() == cbak) {
+            if (r.pkg.equals(pkg) && r.callback.asBinder().equals(cbak)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    @GuardedBy("mToastQueue")
+    int indexOfToastPackageLocked(String pkg)
+    {
+        ArrayList<ToastRecord> list = mToastQueue;
+        int len = list.size();
+        for (int i=0; i<len; i++) {
+            ToastRecord r = list.get(i);
+            if (r.pkg.equals(pkg)) {
                 return i;
             }
         }
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 2f4f5ab..698d387 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -39,6 +39,7 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 
@@ -149,6 +150,17 @@
         String[] classLoaderContexts = DexoptUtils.getClassLoaderContexts(
                 pkg.applicationInfo, sharedLibraries);
 
+        // Sanity check that we do not call dexopt with inconsistent data.
+        if (paths.size() != classLoaderContexts.length) {
+            String[] splitCodePaths = pkg.applicationInfo.getSplitCodePaths();
+            throw new IllegalStateException("Inconsistent information "
+                + "between PackageParser.Package and its ApplicationInfo. "
+                + "pkg.getAllCodePaths=" + paths
+                + " pkg.applicationInfo.getBaseCodePath=" + pkg.applicationInfo.getBaseCodePath()
+                + " pkg.applicationInfo.getSplitCodePaths="
+                + (splitCodePaths == null ? "null" : Arrays.toString(splitCodePaths)));
+        }
+
         int result = DEX_OPT_SKIPPED;
         for (int i = 0; i < paths.size(); i++) {
             // Skip paths that have no code.
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 082dd2b..0ecb4e1 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -274,9 +274,6 @@
         @Override
         public boolean handleMessage(Message msg) {
             synchronized (mLock) {
-                if (msg.obj != null) {
-                    mRemoteObserver = (IPackageInstallObserver2) msg.obj;
-                }
                 try {
                     commitLocked();
                 } catch (PackageManagerException e) {
@@ -666,7 +663,7 @@
     }
 
     @Override
-    public void commit(IntentSender statusReceiver, boolean forTransfer) {
+    public void commit(@NonNull IntentSender statusReceiver, boolean forTransfer) {
         Preconditions.checkNotNull(statusReceiver);
 
         // Cache package manager data without the lock held
@@ -679,6 +676,10 @@
             assertCallerIsOwnerOrRootLocked();
             assertPreparedAndNotDestroyedLocked("commit");
 
+            final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
+                    mContext, statusReceiver, sessionId, isInstallerDeviceOwnerLocked(), userId);
+            mRemoteObserver = adapter.getBinder();
+
             if (forTransfer) {
                 mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, null);
 
@@ -712,9 +713,7 @@
             mActiveCount.incrementAndGet();
 
             mCommitted = true;
-            final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter(
-                    mContext, statusReceiver, sessionId, isInstallerDeviceOwnerLocked(), userId);
-            mHandler.obtainMessage(MSG_COMMIT, adapter.getBinder()).sendToTarget();
+            mHandler.obtainMessage(MSG_COMMIT).sendToTarget();
         }
 
         if (!wasSealed) {
@@ -1422,8 +1421,8 @@
     }
 
     private void dispatchSessionFinished(int returnCode, String msg, Bundle extras) {
-        IPackageInstallObserver2 observer;
-        String packageName;
+        final IPackageInstallObserver2 observer;
+        final String packageName;
         synchronized (mLock) {
             mFinalStatus = returnCode;
             mFinalMessage = msg;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 99261ad..88d7cf8 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7007,22 +7007,44 @@
 
                             // Okay we found a previously set preferred or last chosen app.
                             // If the result set is different from when this
-                            // was created, we need to clear it and re-ask the
-                            // user their preference, if we're looking for an "always" type entry.
+                            // was created, and is not a subset of the preferred set, we need to
+                            // clear it and re-ask the user their preference, if we're looking for
+                            // an "always" type entry.
                             if (always && !pa.mPref.sameSet(query)) {
-                                Slog.i(TAG, "Result set changed, dropping preferred activity for "
-                                        + intent + " type " + resolvedType);
-                                if (DEBUG_PREFERRED) {
-                                    Slog.v(TAG, "Removing preferred activity since set changed "
-                                            + pa.mPref.mComponent);
+                                if (pa.mPref.isSuperset(query)) {
+                                    // some components of the set are no longer present in
+                                    // the query, but the preferred activity can still be reused
+                                    if (DEBUG_PREFERRED) {
+                                        Slog.i(TAG, "Result set changed, but PreferredActivity is"
+                                                + " still valid as only non-preferred components"
+                                                + " were removed for " + intent + " type "
+                                                + resolvedType);
+                                    }
+                                    // remove obsolete components and re-add the up-to-date filter
+                                    PreferredActivity freshPa = new PreferredActivity(pa,
+                                            pa.mPref.mMatch,
+                                            pa.mPref.discardObsoleteComponents(query),
+                                            pa.mPref.mComponent,
+                                            pa.mPref.mAlways);
+                                    pir.removeFilter(pa);
+                                    pir.addFilter(freshPa);
+                                    changed = true;
+                                } else {
+                                    Slog.i(TAG,
+                                            "Result set changed, dropping preferred activity for "
+                                                    + intent + " type " + resolvedType);
+                                    if (DEBUG_PREFERRED) {
+                                        Slog.v(TAG, "Removing preferred activity since set changed "
+                                                + pa.mPref.mComponent);
+                                    }
+                                    pir.removeFilter(pa);
+                                    // Re-add the filter as a "last chosen" entry (!always)
+                                    PreferredActivity lastChosen = new PreferredActivity(
+                                            pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false);
+                                    pir.addFilter(lastChosen);
+                                    changed = true;
+                                    return null;
                                 }
-                                pir.removeFilter(pa);
-                                // Re-add the filter as a "last chosen" entry (!always)
-                                PreferredActivity lastChosen = new PreferredActivity(
-                                        pa, pa.mPref.mMatch, null, pa.mPref.mComponent, false);
-                                pir.addFilter(lastChosen);
-                                changed = true;
-                                return null;
                             }
 
                             // Yay! Either the set matched or we're looking for the last chosen
@@ -18606,36 +18628,6 @@
                     Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
                 }
             }
-
-            // dexopt can take some time to complete, so, for instant apps, we skip this
-            // step during installation. Instead, we'll take extra time the first time the
-            // instant app starts. It's preferred to do it this way to provide continuous
-            // progress to the user instead of mysteriously blocking somewhere in the
-            // middle of running an instant app. The default behaviour can be overridden
-            // via gservices.
-            if (!instantApp || Global.getInt(
-                        mContext.getContentResolver(), Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0) {
-                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
-                // Do not run PackageDexOptimizer through the local performDexOpt
-                // method because `pkg` may not be in `mPackages` yet.
-                //
-                // Also, don't fail application installs if the dexopt step fails.
-                DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
-                        REASON_INSTALL,
-                        DexoptOptions.DEXOPT_BOOT_COMPLETE);
-                mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
-                        null /* instructionSets */,
-                        getOrCreateCompilerPackageStats(pkg),
-                        mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
-                        dexoptOptions);
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-            }
-
-            // Notify BackgroundDexOptService that the package has been changed.
-            // If this is an update of a package which used to fail to compile,
-            // BDOS will remove it from its blacklist.
-            // TODO: Layering violation
-            BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
         }
 
         if (!args.doRename(res.returnCode, pkg, oldCodePath)) {
@@ -18643,6 +18635,50 @@
             return;
         }
 
+        // Verify if we need to dexopt the app.
+        //
+        // NOTE: it is *important* to call dexopt after doRename which will sync the
+        // package data from PackageParser.Package and its corresponding ApplicationInfo.
+        //
+        // We only need to dexopt if the package meets ALL of the following conditions:
+        //   1) it is not forward locked.
+        //   2) it is not on on an external ASEC container.
+        //   3) it is not an instant app or if it is then dexopt is enabled via gservices.
+        //
+        // Note that we do not dexopt instant apps by default. dexopt can take some time to
+        // complete, so we skip this step during installation. Instead, we'll take extra time
+        // the first time the instant app starts. It's preferred to do it this way to provide
+        // continuous progress to the useur instead of mysteriously blocking somewhere in the
+        // middle of running an instant app. The default behaviour can be overridden
+        // via gservices.
+        final boolean performDexopt = !forwardLocked
+            && !pkg.applicationInfo.isExternalAsec()
+            && (!instantApp || Global.getInt(mContext.getContentResolver(),
+                    Global.INSTANT_APP_DEXOPT_ENABLED, 0) != 0);
+
+        if (performDexopt) {
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+            // Do not run PackageDexOptimizer through the local performDexOpt
+            // method because `pkg` may not be in `mPackages` yet.
+            //
+            // Also, don't fail application installs if the dexopt step fails.
+            DexoptOptions dexoptOptions = new DexoptOptions(pkg.packageName,
+                REASON_INSTALL,
+                DexoptOptions.DEXOPT_BOOT_COMPLETE);
+            mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+                null /* instructionSets */,
+                getOrCreateCompilerPackageStats(pkg),
+                mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
+                dexoptOptions);
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        }
+
+        // Notify BackgroundDexOptService that the package has been changed.
+        // If this is an update of a package which used to fail to compile,
+        // BackgroundDexOptService will remove it from its blacklist.
+        // TODO: Layering violation
+        BackgroundDexOptService.notifyPackageChanged(pkg.packageName);
+
         startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
 
         try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
diff --git a/services/core/java/com/android/server/pm/PreferredComponent.java b/services/core/java/com/android/server/pm/PreferredComponent.java
index 8e2e0cd..0f4df97 100644
--- a/services/core/java/com/android/server/pm/PreferredComponent.java
+++ b/services/core/java/com/android/server/pm/PreferredComponent.java
@@ -30,6 +30,7 @@
 
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.List;
 
 public class PreferredComponent {
@@ -241,6 +242,54 @@
         return numMatch == NS;
     }
 
+    public boolean isSuperset(List<ResolveInfo> query) {
+        if (mSetPackages == null) {
+            return query == null;
+        }
+        if (query == null) {
+            return true;
+        }
+        final int NQ = query.size();
+        final int NS = mSetPackages.length;
+        if (NS < NQ) {
+            return false;
+        }
+        for (int i=0; i<NQ; i++) {
+            ResolveInfo ri = query.get(i);
+            ActivityInfo ai = ri.activityInfo;
+            boolean foundMatch = false;
+            for (int j=0; j<NS; j++) {
+                if (mSetPackages[j].equals(ai.packageName) && mSetClasses[j].equals(ai.name)) {
+                    foundMatch = true;
+                    break;
+                }
+            }
+            if (!foundMatch) return false;
+        }
+        return true;
+    }
+
+    /** Returns components from mSetPackages that are present in query. */
+    public ComponentName[] discardObsoleteComponents(List<ResolveInfo> query) {
+        if (mSetPackages == null || query == null) {
+            return new ComponentName[0];
+        }
+        final int NQ = query.size();
+        final int NS = mSetPackages.length;
+        ArrayList<ComponentName> aliveComponents = new ArrayList<>();
+        for (int i = 0; i < NQ; i++) {
+            ResolveInfo ri = query.get(i);
+            ActivityInfo ai = ri.activityInfo;
+            for (int j = 0; j < NS; j++) {
+                if (mSetPackages[j].equals(ai.packageName) && mSetClasses[j].equals(ai.name)) {
+                    aliveComponents.add(new ComponentName(mSetPackages[j], mSetClasses[j]));
+                    break;
+                }
+            }
+        }
+        return aliveComponents.toArray(new ComponentName[aliveComponents.size()]);
+    }
+
     public void dump(PrintWriter out, String prefix, Object ident) {
         out.print(prefix); out.print(
                 Integer.toHexString(System.identityHashCode(ident)));
diff --git a/services/core/java/com/android/server/pm/UserDataPreparer.java b/services/core/java/com/android/server/pm/UserDataPreparer.java
index fc00acc..b8b00af 100644
--- a/services/core/java/com/android/server/pm/UserDataPreparer.java
+++ b/services/core/java/com/android/server/pm/UserDataPreparer.java
@@ -99,8 +99,7 @@
         } catch (Exception e) {
             logCriticalInfo(Log.WARN, "Destroying user " + userId + " on volume " + volumeUuid
                     + " because we failed to prepare: " + e);
-            destroyUserDataLI(volumeUuid, userId,
-                    StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
+            destroyUserDataLI(volumeUuid, userId, flags);
 
             if (allowRecover) {
                 // Try one last time; if we fail again we're really in trouble
diff --git a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
index 85ea3c0..9eb2b46 100644
--- a/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
+++ b/services/core/java/com/android/server/wm/SurfaceControlWithBackground.java
@@ -170,6 +170,11 @@
         // Track overall progress of animation by computing cropped portion of status bar.
         final Rect contentInsets = mWindowSurfaceController.mAnimator.mWin.mContentInsets;
         float d = contentInsets.top == 0 ? 0 : (float) crop.top / contentInsets.top;
+        if (d > 1.f) {
+            // We're running expand animation from launcher, won't compute custom bg crop here.
+            mTmpContainerRect.set(crop);
+            return;
+        }
 
         // Compute additional offset for the background when app window is positioned not at (0,0).
         // E.g. landscape with navigation bar on the left.
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 651cc7d..bf9f941 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -11,6 +11,7 @@
     $(LOCAL_REL_DIR)/BroadcastRadio/Tuner.cpp \
     $(LOCAL_REL_DIR)/BroadcastRadio/TunerCallback.cpp \
     $(LOCAL_REL_DIR)/BroadcastRadio/convert.cpp \
+    $(LOCAL_REL_DIR)/BroadcastRadio/regions.cpp \
     $(LOCAL_REL_DIR)/com_android_server_AlarmManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_am_BatteryStatsService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \
diff --git a/services/core/jni/BroadcastRadio/convert.cpp b/services/core/jni/BroadcastRadio/convert.cpp
index 3e0bc63..ae278de 100644
--- a/services/core/jni/BroadcastRadio/convert.cpp
+++ b/services/core/jni/BroadcastRadio/convert.cpp
@@ -19,6 +19,8 @@
 
 #include "convert.h"
 
+#include "regions.h"
+
 #include <broadcastradio-utils/Utils.h>
 #include <core_jni_helpers.h>
 #include <nativehelper/JNIHelp.h>
@@ -29,8 +31,11 @@
 namespace BroadcastRadio {
 namespace convert {
 
+namespace utils = V1_1::utils;
+
 using hardware::Return;
 using hardware::hidl_vec;
+using regions::RegionalBandConfig;
 
 using V1_0::Band;
 using V1_0::Deemphasis;
@@ -43,6 +48,7 @@
 using V1_1::ProgramSelector;
 using V1_1::VendorKeyValue;
 
+static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const RegionalBandConfig &config);
 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region);
 
 static struct {
@@ -334,9 +340,10 @@
     auto jSerial = make_javastr(env, prop10.serial);
     bool isBgScanSupported = prop11 ? prop11->supportsBackgroundScanning : false;
     auto jVendorInfo = prop11 ? VendorInfoFromHal(env, prop11->vendorInfo) : nullptr;
-    // ITU_1 is the default region just because its index is 0.
-    auto jBands = ArrayFromHal<V1_0::BandConfig>(env, prop10.bands, gjni.BandDescriptor.clazz,
-        std::bind(BandDescriptorFromHal, _1, _2, Region::ITU_1));
+
+    auto regionalBands = regions::mapRegions(prop10.bands);
+    auto jBands = ArrayFromHal<RegionalBandConfig>(env, regionalBands,
+            gjni.BandDescriptor.clazz, BandDescriptorFromHal);
     auto jSupportedProgramTypes =
             prop11 ? ArrayFromHal(env, prop11->supportedProgramTypes) : nullptr;
     auto jSupportedIdentifierTypes =
@@ -359,32 +366,31 @@
     return ModulePropertiesFromHal(env, properties.base, &properties, moduleId, serviceName);
 }
 
+static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const RegionalBandConfig &config) {
+    return BandDescriptorFromHal(env, config.bandConfig, config.region);
+}
+
 static JavaRef<jobject> BandDescriptorFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region) {
     ALOGV("%s", __func__);
 
     jint spacing = config.spacings.size() > 0 ? config.spacings[0] : 0;
+    ALOGW_IF(config.spacings.size() > 1, "Multiple spacings - not a regional config");
     ALOGW_IF(config.spacings.size() == 0, "No channel spacing specified");
 
-    switch (config.type) {
-        case Band::FM:
-        case Band::FM_HD: {
-            auto& fm = config.ext.fm;
-            return make_javaref(env, env->NewObject(
-                    gjni.FmBandDescriptor.clazz, gjni.FmBandDescriptor.cstor,
-                    region, config.type, config.lowerLimit, config.upperLimit, spacing,
-                    fm.stereo, fm.rds != Rds::NONE, fm.ta, fm.af, fm.ea));
-        }
-        case Band::AM:
-        case Band::AM_HD: {
-            auto& am = config.ext.am;
-            return make_javaref(env, env->NewObject(
-                    gjni.AmBandDescriptor.clazz, gjni.AmBandDescriptor.cstor,
-                    region, config.type, config.lowerLimit, config.upperLimit, spacing,
-                    am.stereo));
-        }
-        default:
-            ALOGE("Unsupported band type: %d", config.type);
-            return nullptr;
+    if (utils::isFm(config.type)) {
+        auto& fm = config.ext.fm;
+        return make_javaref(env, env->NewObject(
+                gjni.FmBandDescriptor.clazz, gjni.FmBandDescriptor.cstor,
+                region, config.type, config.lowerLimit, config.upperLimit, spacing,
+                fm.stereo, fm.rds != Rds::NONE, fm.ta, fm.af, fm.ea));
+    } else if (utils::isAm(config.type)) {
+        auto& am = config.ext.am;
+        return make_javaref(env, env->NewObject(
+                gjni.AmBandDescriptor.clazz, gjni.AmBandDescriptor.cstor,
+                region, config.type, config.lowerLimit, config.upperLimit, spacing, am.stereo));
+    } else {
+        ALOGE("Unsupported band type: %d", config.type);
+        return nullptr;
     }
 }
 
@@ -394,20 +400,15 @@
     auto descriptor = BandDescriptorFromHal(env, config, region);
     if (descriptor == nullptr) return nullptr;
 
-    switch (config.type) {
-        case Band::FM:
-        case Band::FM_HD: {
-            return make_javaref(env, env->NewObject(
-                    gjni.FmBandConfig.clazz, gjni.FmBandConfig.cstor, descriptor.get()));
-        }
-        case Band::AM:
-        case Band::AM_HD: {
-            return make_javaref(env, env->NewObject(
-                    gjni.AmBandConfig.clazz, gjni.AmBandConfig.cstor, descriptor.get()));
-        }
-        default:
-            ALOGE("Unsupported band type: %d", config.type);
-            return nullptr;
+    if (utils::isFm(config.type)) {
+        return make_javaref(env, env->NewObject(
+                gjni.FmBandConfig.clazz, gjni.FmBandConfig.cstor, descriptor.get()));
+    } else if (utils::isAm(config.type)) {
+        return make_javaref(env, env->NewObject(
+                gjni.AmBandConfig.clazz, gjni.AmBandConfig.cstor, descriptor.get()));
+    } else {
+        ALOGE("Unsupported band type: %d", config.type);
+        return nullptr;
     }
 }
 
@@ -583,7 +584,7 @@
 }
 
 JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_0::ProgramInfo &info, V1_0::Band band) {
-    auto selector = V1_1::utils::make_selector(band, info.channel, info.subChannel);
+    auto selector = utils::make_selector(band, info.channel, info.subChannel);
     return ProgramInfoFromHal(env, info, nullptr, selector);
 }
 
diff --git a/services/core/jni/BroadcastRadio/regions.cpp b/services/core/jni/BroadcastRadio/regions.cpp
new file mode 100644
index 0000000..e313521
--- /dev/null
+++ b/services/core/jni/BroadcastRadio/regions.cpp
@@ -0,0 +1,196 @@
+/**
+ * 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.
+ */
+
+#define LOG_TAG "BroadcastRadioService.regions.jni"
+#define LOG_NDEBUG 0
+
+#include "regions.h"
+
+#include <broadcastradio-utils/Utils.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace server {
+namespace BroadcastRadio {
+namespace regions {
+
+namespace utils = hardware::broadcastradio::V1_1::utils;
+
+using hardware::hidl_vec;
+
+using V1_0::Band;
+using V1_0::BandConfig;
+using V1_0::Deemphasis;
+using V1_0::Rds;
+
+class RegionalBandDefinition {
+public:
+    std::vector<Region> mRegions;
+    std::vector<Band> mTypes;
+    uint32_t mLowerLimit;
+    uint32_t mUpperLimit;
+    uint32_t mSpacing;
+
+    Deemphasis mFmDeemphasis = {};
+    Rds mFmRds = Rds::NONE;
+
+    bool fitsInsideBand(const BandConfig &bandConfig) const;
+    std::vector<RegionalBandConfig> withConfig(BandConfig bandConfig) const;
+};
+
+static const RegionalBandDefinition kKnownRegionConfigs[] = {
+    {
+        { Region::ITU_1 },
+        { Band::FM },
+        87500,
+        108000,
+        100,
+        Deemphasis::D50,
+        Rds::WORLD,
+    },
+    {
+        { Region::ITU_2 },
+        { Band::FM, Band::FM_HD },
+        87900,
+        107900,
+        200,
+        Deemphasis::D75,
+        Rds::US,
+    },
+    {
+        { Region::OIRT },
+        { Band::FM },
+        65800,
+        74000,
+        10,
+        Deemphasis::D50,
+        Rds::WORLD,
+    },
+    {
+        { Region::JAPAN },
+        { Band::FM },
+        76000,
+        90000,
+        100,
+        Deemphasis::D50,
+        Rds::WORLD,
+    },
+    {
+        { Region::KOREA },
+        { Band::FM },
+        87500,
+        108000,
+        100,
+        Deemphasis::D75,
+        Rds::WORLD,
+    },
+    {  // AM LW
+        { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
+        { Band::AM },
+        153,
+        279,
+        9,
+    },
+    {  // AM MW
+        { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
+        { Band::AM },
+        531,
+        1611,
+        9,
+    },
+    {  // AM SW
+        { Region::ITU_1, Region::OIRT, Region::JAPAN, Region::KOREA },
+        { Band::AM },
+        2300,
+        26100,
+        5,
+    },
+    {  // AM LW ITU2
+        { Region::ITU_2 },
+        { Band::AM, Band::AM_HD },
+        153,
+        279,
+        9,
+    },
+    {  // AM MW ITU2
+        { Region::ITU_2 },
+        { Band::AM, Band::AM_HD },
+        540,
+        1610,
+        10,
+    },
+    {  // AM SW ITU2
+        { Region::ITU_2 },
+        { Band::AM, Band::AM_HD },
+        2300,
+        26100,
+        5,
+    },
+};
+
+bool RegionalBandDefinition::fitsInsideBand(const BandConfig &bandConfig) const {
+    if (std::find(mTypes.begin(), mTypes.end(), bandConfig.type) == mTypes.end()) return false;
+    if (mLowerLimit < bandConfig.lowerLimit) return false;
+    if (mUpperLimit > bandConfig.upperLimit) return false;
+    auto&& spacings = bandConfig.spacings;
+    if (std::find(spacings.begin(), spacings.end(), mSpacing) == spacings.end()) return false;
+    if (utils::isFm(bandConfig.type)) {
+        if (0 == (mFmDeemphasis & bandConfig.ext.fm.deemphasis)) return false;
+    }
+
+    return true;
+}
+
+std::vector<RegionalBandConfig> RegionalBandDefinition::withConfig(BandConfig config) const {
+    config.lowerLimit = mLowerLimit;
+    config.upperLimit = mUpperLimit;
+    config.spacings = hidl_vec<uint32_t>({ mSpacing });
+    if (utils::isFm(config.type)) {
+        auto&& fm = config.ext.fm;
+        fm.deemphasis = mFmDeemphasis;
+        fm.rds = static_cast<Rds>(mFmRds & fm.rds);
+    }
+
+    std::vector<RegionalBandConfig> configs;
+    for (auto region : mRegions) {
+        configs.push_back({region, config});
+    }
+
+    return configs;
+}
+
+std::vector<RegionalBandConfig> mapRegions(const hidl_vec<BandConfig>& bands) {
+    ALOGV("%s", __func__);
+
+    std::vector<RegionalBandConfig> out;
+
+    for (auto&& regionalBand : kKnownRegionConfigs) {
+        for (auto&& tunerBand : bands) {
+            if (regionalBand.fitsInsideBand(tunerBand)) {
+                auto mapped = regionalBand.withConfig(tunerBand);
+                out.insert(out.end(), mapped.begin(), mapped.end());
+            }
+        }
+    }
+
+    ALOGI("Mapped %zu tuner bands to %zu regional bands", bands.size(), out.size());
+    return out;
+}
+
+} // namespace regions
+} // namespace BroadcastRadio
+} // namespace server
+} // namespace android
diff --git a/services/core/jni/BroadcastRadio/regions.h b/services/core/jni/BroadcastRadio/regions.h
new file mode 100644
index 0000000..45a32ea
--- /dev/null
+++ b/services/core/jni/BroadcastRadio/regions.h
@@ -0,0 +1,44 @@
+/**
+ * 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.
+ */
+
+#ifndef _ANDROID_SERVER_BROADCASTRADIO_REGIONS_H
+#define _ANDROID_SERVER_BROADCASTRADIO_REGIONS_H
+
+#include "types.h"
+
+#include <android/hardware/broadcastradio/1.1/types.h>
+
+namespace android {
+namespace server {
+namespace BroadcastRadio {
+namespace regions {
+
+namespace V1_0 = hardware::broadcastradio::V1_0;
+
+struct RegionalBandConfig {
+    Region region;
+    V1_0::BandConfig bandConfig;
+};
+
+std::vector<RegionalBandConfig>
+mapRegions(const hardware::hidl_vec<V1_0::BandConfig>& bands);
+
+} // namespace regions
+} // namespace BroadcastRadio
+} // namespace server
+} // namespace android
+
+#endif // _ANDROID_SERVER_BROADCASTRADIO_REGIONS_H
diff --git a/telecomm/java/android/telecom/RemoteConnection.java b/telecomm/java/android/telecom/RemoteConnection.java
index 57fc9ce..f30d7bd 100644
--- a/telecomm/java/android/telecom/RemoteConnection.java
+++ b/telecomm/java/android/telecom/RemoteConnection.java
@@ -25,6 +25,7 @@
 import android.annotation.SystemApi;
 import android.hardware.camera2.CameraManager;
 import android.net.Uri;
+import android.os.BadParcelableException;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -1464,7 +1465,11 @@
         if (mExtras == null) {
             mExtras = new Bundle();
         }
-        mExtras.putAll(extras);
+        try {
+            mExtras.putAll(extras);
+        } catch (BadParcelableException bpe) {
+            Log.w(this, "putExtras: could not unmarshal extras; exception = " + bpe);
+        }
 
         notifyExtrasChanged();
     }
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 68fd825..7e08f51 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -321,6 +321,7 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
     @Override
     public String[] getNamesForUids(int uid[]) {
         throw new UnsupportedOperationException();