Merge "update trust state immediately when user auths via FP on keyguard"
diff --git a/Android.bp b/Android.bp
index 81d6dab..4ab5f1f 100644
--- a/Android.bp
+++ b/Android.bp
@@ -12,7 +12,46 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+// ====  c++ proto device library  ==============================
+cc_library {
+    name: "libplatformprotos",
+    host_supported: true,
+    // b/34740546, work around clang-tidy segmentation fault.
+    tidy_checks: ["-modernize*"],
+    proto: {
+        export_proto_headers: true,
+        include_dirs: ["external/protobuf/src"],
+    },
+
+    target: {
+        host: {
+            proto: {
+                type: "full",
+            },
+        },
+        android: {
+            proto: {
+                type: "lite",
+            },
+            shared: {
+                // The proto files generate full protos, but we only use
+                // them as lite on device.  This works fine for a static
+                // library, where the unused full symbols are stripped,
+                // but fails if it is linked as a standalone shared
+                // library because it is missing the full runtime.
+                enabled: false,
+            },
+        },
+    },
+
+    srcs: [
+        "core/proto/**/*.proto",
+        "libs/incident/**/*.proto",
+    ],
+}
+
 subdirs = [
+    "core/jni",
     "libs/*",
     "tools/*",
     "native/android",
diff --git a/Android.mk b/Android.mk
index 8bb366a..c10a0cc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -114,6 +114,8 @@
 	core/java/android/app/backup/IRestoreObserver.aidl \
 	core/java/android/app/backup/IRestoreSession.aidl \
 	core/java/android/app/backup/ISelectBackupTransportCallback.aidl \
+	core/java/android/app/timezone/ICallback.aidl \
+	core/java/android/app/timezone/IRulesManager.aidl \
 	core/java/android/app/usage/ICacheQuotaService.aidl \
 	core/java/android/app/usage/IStorageStatsManager.aidl \
 	core/java/android/app/usage/IUsageStatsManager.aidl \
@@ -1478,35 +1480,6 @@
 
 include $(BUILD_JAVA_LIBRARY)
 
-# ====  c++ proto device library  ==============================
-include $(CLEAR_VARS)
-LOCAL_MODULE := libplatformprotos
-# b/34740546, work around clang-tidy segmentation fault.
-LOCAL_TIDY_CHECKS := -modernize*
-LOCAL_PROTOC_OPTIMIZE_TYPE := lite
-LOCAL_PROTOC_FLAGS := \
-    --include_source_info \
-    -Iexternal/protobuf/src
-LOCAL_SRC_FILES := \
-    $(call all-proto-files-under, core/proto) \
-    $(call all-proto-files-under, libs/incident/proto)
-include $(BUILD_STATIC_LIBRARY)
-
-# ====  c++ proto host library  ==============================
-include $(CLEAR_VARS)
-LOCAL_MODULE := libplatformprotos
-# b/34740546, work around clang-tidy segmentation fault.
-LOCAL_TIDY_CHECKS := -modernize*
-LOCAL_PROTOC_OPTIMIZE_TYPE := full
-LOCAL_PROTOC_FLAGS := \
-    --include_source_info \
-    -Iexternal/protobuf/src
-LOCAL_SRC_FILES := \
-    $(call all-proto-files-under, core/proto) \
-    $(call all-proto-files-under, libs/incident/proto)
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
 # ====  java proto host library  ==============================
 include $(CLEAR_VARS)
 LOCAL_MODULE := platformprotos
diff --git a/api/current.txt b/api/current.txt
index 6efa792..0cb71a0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -30528,7 +30528,7 @@
     field public static final int M = 23; // 0x17
     field public static final int N = 24; // 0x18
     field public static final int N_MR1 = 25; // 0x19
-    field public static final int O = 26; // 0x1a
+    field public static final int O = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -43979,6 +43979,7 @@
     method public android.os.Vibrator getVibrator();
     method public boolean[] hasKeys(int...);
     method public boolean hasMicrophone();
+    method public boolean isEnabled();
     method public boolean isVirtual();
     method public boolean supportsSource(int);
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/system-current.txt b/api/system-current.txt
index 4124ad3..738ea33 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -33245,7 +33245,7 @@
     field public static final int M = 23; // 0x17
     field public static final int N = 24; // 0x18
     field public static final int N_MR1 = 25; // 0x19
-    field public static final int O = 26; // 0x1a
+    field public static final int O = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -47526,6 +47526,7 @@
     method public android.os.Vibrator getVibrator();
     method public boolean[] hasKeys(int...);
     method public boolean hasMicrophone();
+    method public boolean isEnabled();
     method public boolean isVirtual();
     method public boolean supportsSource(int);
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/api/test-current.txt b/api/test-current.txt
index a4e1866..a1850f5 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -30637,7 +30637,7 @@
     field public static final int M = 23; // 0x17
     field public static final int N = 24; // 0x18
     field public static final int N_MR1 = 25; // 0x19
-    field public static final int O = 26; // 0x1a
+    field public static final int O = 10000; // 0x2710
   }
 
   public final class Bundle extends android.os.BaseBundle implements java.lang.Cloneable android.os.Parcelable {
@@ -44344,6 +44344,8 @@
 
   public final class InputDevice implements android.os.Parcelable {
     method public int describeContents();
+    method public void disable();
+    method public void enable();
     method public int getControllerNumber();
     method public java.lang.String getDescriptor();
     method public static android.view.InputDevice getDevice(int);
@@ -44361,6 +44363,7 @@
     method public android.os.Vibrator getVibrator();
     method public boolean[] hasKeys(int...);
     method public boolean hasMicrophone();
+    method public boolean isEnabled();
     method public boolean isVirtual();
     method public boolean supportsSource(int);
     method public void writeToParcel(android.os.Parcel, int);
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index deb5b31..588a1bf 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -1441,10 +1441,10 @@
             System.err.println("Error: no size specified");
             return showUsage();
         }
-        int len = size.length();
         long multiplier = 1;
-        if (len > 1) {
-            char c = size.charAt(len-1);
+        int len = size.length();
+        char c = size.charAt(len - 1);
+        if (c < '0' || c > '9') {
             if (c == 'K' || c == 'k') {
                 multiplier = 1024L;
             } else if (c == 'M' || c == 'm') {
diff --git a/cmds/uiautomator/instrumentation/Android.mk b/cmds/uiautomator/instrumentation/Android.mk
index 0c93b4c..e6cbdb4 100644
--- a/cmds/uiautomator/instrumentation/Android.mk
+++ b/cmds/uiautomator/instrumentation/Android.mk
@@ -22,6 +22,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, testrunner-src) \
     $(call all-java-files-under, ../library/core-src)
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
 LOCAL_MODULE := uiautomator-instrumentation
 # TODO: change this to 18 when it's available
 LOCAL_SDK_VERSION := current
diff --git a/cmds/vr/src/com/android/commands/vr/Vr.java b/cmds/vr/src/com/android/commands/vr/Vr.java
index bf97bba..b765866 100644
--- a/cmds/vr/src/com/android/commands/vr/Vr.java
+++ b/cmds/vr/src/com/android/commands/vr/Vr.java
@@ -16,7 +16,7 @@
 
 package com.android.commands.vr;
 
-import android.app.CompatibilityDisplayProperties;
+import android.app.Vr2dDisplayProperties;
 import android.content.Context;
 import android.os.RemoteException;
 import android.os.ServiceManager;
@@ -39,7 +39,7 @@
 
     private static final String COMMAND_SET_PERSISTENT_VR_MODE_ENABLED =
         "set-persistent-vr-mode-enabled";
-    private static final String COMMAND_SET_COMPATIBILITY_DISPLAY_PROPERTIES =
+    private static final String COMMAND_SET_VR2D_DISPLAY_PROPERTIES =
         "set-display-props";
 
     private IVrManager mVrService;
@@ -63,8 +63,8 @@
 
         String command = nextArgRequired();
         switch (command) {
-            case COMMAND_SET_COMPATIBILITY_DISPLAY_PROPERTIES:
-                runSetCompatibilityDisplayProperties();
+            case COMMAND_SET_VR2D_DISPLAY_PROPERTIES:
+                runSetVr2dDisplayProperties();
                 break;
             case COMMAND_SET_PERSISTENT_VR_MODE_ENABLED:
                 runSetPersistentVrModeEnabled();
@@ -74,7 +74,7 @@
         }
     }
 
-    private void runSetCompatibilityDisplayProperties() throws RemoteException {
+    private void runSetVr2dDisplayProperties() throws RemoteException {
         String widthStr = nextArgRequired();
         int width = Integer.parseInt(widthStr);
 
@@ -84,11 +84,11 @@
         String dpiStr = nextArgRequired();
         int dpi = Integer.parseInt(dpiStr);
 
-        CompatibilityDisplayProperties compatDisplayProperties =
-                new CompatibilityDisplayProperties(width, height, dpi);
+        Vr2dDisplayProperties vr2dDisplayProperties =
+                new Vr2dDisplayProperties(width, height, dpi);
 
         try {
-            mVrService.setCompatibilityDisplayProperties(compatDisplayProperties);
+            mVrService.setVr2dDisplayProperties(vr2dDisplayProperties);
         } catch (RemoteException re) {
             System.err.println("Error: Can't set persistent mode " + re);
         }
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index a5b37f3..8fd8043 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -370,15 +370,6 @@
         "android.accounts.action.VISIBLE_ACCOUNTS_CHANGED";
 
     /**
-     * Key to set default visibility for applications targeting API level
-     * {@link android.os.Build.VERSION_CODES#O} or above and don't have the same signature as
-     * authenticator See {@link #getAccountVisibility}. If the value was not set by authenticator
-     * {@link #VISIBILITY_USER_MANAGED_NOT_VISIBLE} is used.
-     */
-    public static final String PACKAGE_NAME_KEY_LEGACY_VISIBLE =
-        "android:accounts:key_legacy_visible";
-
-    /**
      * Key to set visibility for applications which satisfy one of the following conditions:
      * <ul>
      * <li>Target API level below {@link android.os.Build.VERSION_CODES#O} and have
@@ -394,6 +385,14 @@
      * See {@link #getAccountVisibility}. If the value was not set by authenticator
      * {@link #VISIBILITY_USER_MANAGED_VISIBLE} is used.
      */
+    public static final String PACKAGE_NAME_KEY_LEGACY_VISIBLE =
+        "android:accounts:key_legacy_visible";
+
+    /**
+     * Key to set default visibility for applications which don't satisfy conditions in
+     * {@link PACKAGE_NAME_KEY_LEGACY_VISIBLE}. If the value was not set by authenticator
+     * {@link #VISIBILITY_USER_MANAGED_NOT_VISIBLE} is used.
+     */
     public static final String PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE =
             "android:accounts:key_legacy_not_visible";
 
@@ -608,14 +607,17 @@
     }
 
     /**
-     * Returns the accounts visible to the specified package, in an environment where some apps are
+     * Returns the accounts visible to the specified package in an environment where some apps are
      * not authorized to view all accounts. This method can only be called by system apps and
-     * authenticators managing the type
+     * authenticators managing the type.
+     * Beginning API level {@link android.os.Build.VERSION_CODES#O} it also return accounts
+     * which user can make visible to the application (see {@link VISIBILITY_USER_MANAGED_VISIBLE}).
      *
      * @param type The type of accounts to return, null to retrieve all accounts
      * @param packageName The package name of the app for which the accounts are to be returned
      * @return An array of {@link Account}, one per matching account. Empty (never null) if no
-     *         accounts of the specified type have been added.
+     *         accounts of the specified type can be accessed by the package.
+     *
      */
     @NonNull
     public Account[] getAccountsByTypeForPackage(String type, String packageName) {
@@ -644,7 +646,10 @@
      *
      * <p>
      * Caller targeting API level {@link android.os.Build.VERSION_CODES#O} and above, will get list
-     * of accounts made visible to it by user or AbstractAcccountAuthenticator and
+     * of accounts made visible to it by user
+     * (see {@link #newChooseAccountIntent(Account, List, String[], String,
+     * String, String[], Bundle)}) or AbstractAcccountAuthenticator
+     * using {@link setAccountVisibility}.
      * {@link android.Manifest.permission#GET_ACCOUNTS} permission is not used.
      *
      * <p>
@@ -787,7 +792,10 @@
      *
      * <p>
      * Caller targeting API level {@link android.os.Build.VERSION_CODES#O} and above, will get list
-     * of accounts made visible to it by user or AbstractAcccountAuthenticator and
+     * of accounts made visible to it by user
+     * (see {@link #newChooseAccountIntent(Account, List, String[], String,
+     * String, String[], Bundle)}) or AbstractAcccountAuthenticator
+     * using {@link setAccountVisibility}.
      * {@link android.Manifest.permission#GET_ACCOUNTS} permission is not used.
      *
      * <p>
@@ -869,7 +877,7 @@
     }
 
     /**
-     * Adds an account directly to the AccountManager. Additionally it specifies Account visiblity
+     * Adds an account directly to the AccountManager. Additionally it specifies Account visibility
      * for given list of packages.
      * <p>
      * Normally used by sign-up wizards associated with authenticators, not directly by
@@ -2663,8 +2671,8 @@
      *
      * <p>
      * This method gets a list of the accounts matching specific type and feature set which are
-     * visible to the caller or for which user can grant access (see {@link #getAccountsByType} for
-     * details); if there is exactly one already visible account, it is used; if there are some
+     * visible to the caller (see {@link #getAccountsByType} for details);
+     * if there is exactly one already visible account, it is used; if there are some
      * accounts for which user grant visibility, the user is prompted to pick one; if there are
      * none, the user is prompted to add one. Finally, an auth token is acquired for the chosen
      * account.
@@ -2735,6 +2743,9 @@
      * <p>
      * On success the activity returns a Bundle with the account name and type specified using
      * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
+     * Chosen account is marked as {@link #VISIBILITY_USER_MANAGED_VISIBLE} to the caller
+     * (see {@link setAccountVisibility}) and will be returned to it in consequent
+     * {@link #getAccountsByType}) calls.
      * <p>
      * The most common case is to call this with one account type, e.g.:
      * <p>
@@ -2787,6 +2798,9 @@
      * <p>
      * On success the activity returns a Bundle with the account name and type specified using
      * keys {@link #KEY_ACCOUNT_NAME} and {@link #KEY_ACCOUNT_TYPE}.
+     * Chosen account is marked as {@link #VISIBILITY_USER_MANAGED_VISIBLE} to the caller
+     * (see {@link setAccountVisibility}) and will be returned to it in consequent
+     * {@link #getAccountsByType}) calls.
      * <p>
      * The most common case is to call this with one account type, e.g.:
      * <p>
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4f6c0c9..37c287e 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -25,6 +25,7 @@
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.app.ToolbarActionBar;
 import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.policy.DecorView;
 import com.android.internal.policy.PhoneWindow;
 
 import android.annotation.CallSuper;
@@ -3147,19 +3148,6 @@
     }
 
     /**
-     * Called before {@link #onAttachedToWindow}.
-     *
-     * @hide
-     */
-    @CallSuper
-    public void onBeforeAttachedToWindow() {
-        if (mAutoFillResetNeeded) {
-            getAutofillManager().onAttachedToWindow(
-                    getWindow().getDecorView().getRootView().getWindowToken());
-        }
-    }
-
-    /**
      * Called when the main window associated with the activity has been
      * attached to the window manager.
      * See {@link View#onAttachedToWindow() View.onAttachedToWindow()}
@@ -7443,7 +7431,7 @@
         final int offsetX = (anchorBounds != null)
                 ? anchorBounds.left - actualAnchorBounds.left : 0;
         int offsetY = (anchorBounds != null)
-                ? anchorBounds.top - actualAnchorBounds.top : 0;
+                ? anchorBounds.bottom - actualAnchorBounds.bottom : 0;
 
         final boolean wasShowing;
 
@@ -7471,45 +7459,62 @@
     }
 
     /** @hide */
+    @NonNull public View[] findViewsByAccessibilityIdTraversal(@NonNull int[] viewIds) {
+        final View[] views = new View[viewIds.length];
+        final ArrayList<ViewRootImpl> roots =
+                WindowManagerGlobal.getInstance().getRootViews(getActivityToken());
+
+        for (int rootNum = 0; rootNum < roots.size(); rootNum++) {
+            final View rootView = roots.get(rootNum).getView();
+
+            if (rootView != null) {
+                for (int viewNum = 0; viewNum < viewIds.length; viewNum++) {
+                    if (views[viewNum] == null) {
+                        views[viewNum] = rootView.findViewByAccessibilityIdTraversal(
+                                viewIds[viewNum]);
+                    }
+                }
+            }
+        }
+
+        return views;
+    }
+
+    /** @hide */
     @Override
-    public boolean getViewVisibility(int viewId) {
-        Window window = getWindow();
-        if (window == null) {
-            Log.i(TAG, "no window");
-            return false;
-        }
+    @NonNull public boolean[] getViewVisibility(@NonNull int[] viewIds) {
+        final boolean[] isVisible = new boolean[viewIds.length];
+        final View views[] = findViewsByAccessibilityIdTraversal(viewIds);
 
-        View decorView = window.peekDecorView();
-        if (decorView == null) {
-            Log.i(TAG, "no decorView");
-            return false;
-        }
-
-        View view = decorView.findViewByAccessibilityIdTraversal(viewId);
-        if (view == null) {
-            Log.i(TAG, "cannot find view");
-            return false;
-        }
-
-        // Check if the view is visible by checking all parents
-        while (view != null) {
-            if (view == decorView) {
-                break;
+        for (int i = 0; i < viewIds.length; i++) {
+            View view = views[i];
+            if (view == null) {
+                isVisible[i] = false;
+                continue;
             }
 
-            if (view.getVisibility() != View.VISIBLE) {
-                Log.i(TAG, view + " is not visible");
-                return false;
-            }
+            isVisible[i] = true;
 
-            if (view.getParent() instanceof View) {
-                view = (View) view.getParent();
-            } else {
-                break;
+            // Check if the view is visible by checking all parents
+            while (true) {
+                if (view instanceof DecorView && view.getViewRootImpl() == view.getParent()) {
+                    break;
+                }
+
+                if (view.getVisibility() != View.VISIBLE) {
+                    isVisible[i] = false;
+                    break;
+                }
+
+                if (view.getParent() instanceof View) {
+                    view = (View) view.getParent();
+                } else {
+                    break;
+                }
             }
         }
 
-        return true;
+        return isVisible;
     }
 
     /** @hide */
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 65cb5f4..0dfaf6a 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -244,8 +244,8 @@
 
     /**
      * Called after virtual display Id is updated by
-     * {@link com.android.server.vr.CompatibilityDisplay} with a specific
-     * {@param compatibilityDisplayId}.
+     * {@link com.android.server.vr.Vr2dDisplay} with a specific
+     * {@param vr2dDisplayId}.
      */
-    public abstract void setVrCompatibilityDisplayId(int vrCompatibilityDisplayId);
+    public abstract void setVr2dDisplayId(int vr2dDisplayId);
 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index dd9db8a..928ef7e 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4275,9 +4275,19 @@
             View.mDebugViewAttributes = debugViewAttributes;
 
             // request all activities to relaunch for the changes to take place
-            for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
-                requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false,
-                        false /* preserveWindow */);
+            requestRelaunchAllActivities();
+        }
+    }
+
+    private void requestRelaunchAllActivities() {
+        for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
+            final Activity activity = entry.getValue().activity;
+            if (!activity.mFinished) {
+                try {
+                    ActivityManager.getService().requestActivityRelaunch(entry.getKey());
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
+                }
             }
         }
     }
@@ -5084,24 +5094,26 @@
         // caused by other sources, such as overlays. That means we want to be as conservative
         // about code changes as possible. Take the diff of the old ApplicationInfo and the new
         // to see if anything needs to change.
+        LoadedApk apk;
+        LoadedApk resApk;
+        // Update all affected loaded packages with new package information
         synchronized (mResourcesManager) {
-            // Update all affected loaded packages with new package information
             WeakReference<LoadedApk> ref = mPackages.get(ai.packageName);
-            LoadedApk apk = ref != null ? ref.get() : null;
-            if (apk != null) {
-                final ArrayList<String> oldPaths = new ArrayList<>();
-                LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
-                apk.updateApplicationInfo(ai, oldPaths);
-            }
-
-            ref = mResourcePackages.get(ai.packageName);
             apk = ref != null ? ref.get() : null;
-            if (apk != null) {
-                final ArrayList<String> oldPaths = new ArrayList<>();
-                LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
-                apk.updateApplicationInfo(ai, oldPaths);
-            }
-
+            ref = mResourcePackages.get(ai.packageName);
+            resApk = ref != null ? ref.get() : null;
+        }
+        if (apk != null) {
+            final ArrayList<String> oldPaths = new ArrayList<>();
+            LoadedApk.makePaths(this, apk.getApplicationInfo(), oldPaths);
+            apk.updateApplicationInfo(ai, oldPaths);
+        }
+        if (resApk != null) {
+            final ArrayList<String> oldPaths = new ArrayList<>();
+            LoadedApk.makePaths(this, resApk.getApplicationInfo(), oldPaths);
+            resApk.updateApplicationInfo(ai, oldPaths);
+        }
+        synchronized (mResourcesManager) {
             // Update all affected Resources objects to use new ResourcesImpl
             mResourcesManager.applyNewResourceDirsLocked(ai.sourceDir, ai.resourceDirs);
         }
@@ -5116,14 +5128,7 @@
         newConfig.assetsSeq = (mConfiguration != null ? mConfiguration.assetsSeq : 0) + 1;
         handleConfigurationChanged(newConfig, null);
 
-        // Schedule all activities to reload
-        for (final Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
-            final Activity activity = entry.getValue().activity;
-            if (!activity.mFinished) {
-                requestRelaunchActivity(entry.getKey(), null, null, 0, false, null, null, false,
-                        false);
-            }
-        }
+        requestRelaunchAllActivities();
     }
 
     static void freeTextLayoutCachesIfNeeded(int configDiff) {
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index 3221c5d..620e5cf 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -226,11 +226,7 @@
         @Override
         public void doAlarm(IAlarmCompleteListener alarmManager) {
             mCompletion = alarmManager;
-            mHandler.post(this);
-        }
 
-        @Override
-        public void run() {
             // Remove this listener from the wrapper cache first; the server side
             // already considers it gone
             synchronized (AlarmManager.class) {
@@ -239,6 +235,11 @@
                 }
             }
 
+            mHandler.post(this);
+        }
+
+        @Override
+        public void run() {
             // Now deliver it to the app
             try {
                 mListener.onAlarm();
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 63c0ef3..1b2543c 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -2497,7 +2497,6 @@
             mBackStack = new ArrayList<BackStackRecord>();
         }
         mBackStack.add(state);
-        reportBackStackChanged();
     }
 
     boolean popBackStackState(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop,
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index aeccf56..68fce75 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -200,7 +200,7 @@
     void setRequestedOrientation(in IBinder token, int requestedOrientation);
     int getRequestedOrientation(in IBinder token);
     void unbindFinished(in IBinder token, in Intent service, boolean doRebind);
-    void setProcessForeground(in IBinder token, int pid, boolean isForeground);
+    void setProcessImportant(in IBinder token, int pid, boolean isForeground, String reason);
     void setServiceForeground(in ComponentName className, in IBinder token,
             int id, in Notification notification, int flags);
     boolean moveActivityTaskToBack(in IBinder token, boolean nonRoot);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index f369955..4994fbb 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -39,8 +39,11 @@
      * Called whenever IActivityManager.startActivity is called on an activity that is already
      * running in the pinned stack and the activity is not actually started, but the task is either
      * brought to the front or a new Intent is delivered to it.
+     *
+     * @param clearedTask whether or not the launch activity also cleared the task as a part of
+     * starting
      */
-    void onPinnedActivityRestartAttempt();
+    void onPinnedActivityRestartAttempt(boolean clearedTask);
 
     /**
      * Called whenever the pinned stack is starting animating a resize.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 2e56bcf..0041879 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -2675,6 +2675,7 @@
         private int mActionBarColor = COLOR_INVALID;
         private int mBackgroundColor = COLOR_INVALID;
         private int mForegroundColor = COLOR_INVALID;
+        private int mBackgroundColorHint = COLOR_INVALID;
 
         /**
          * Constructs a new Builder with the defaults:
@@ -3839,6 +3840,13 @@
                             backgroundColor);
                     mSecondaryTextColor = NotificationColorUtil.resolveSecondaryColor(mContext,
                             backgroundColor);
+                    if (backgroundColor != COLOR_DEFAULT
+                            && (mBackgroundColorHint != COLOR_INVALID || isColorized())) {
+                        mPrimaryTextColor = NotificationColorUtil.findAlphaToMeetContrast(
+                                mPrimaryTextColor, backgroundColor, 4.5);
+                        mSecondaryTextColor = NotificationColorUtil.findAlphaToMeetContrast(
+                                mSecondaryTextColor, backgroundColor, 4.5);
+                    }
                 } else {
                     double backLum = NotificationColorUtil.calculateLuminance(backgroundColor);
                     double textLum = NotificationColorUtil.calculateLuminance(mForegroundColor);
@@ -4662,10 +4670,26 @@
             if (mCachedContrastColorIsFor == mN.color && mCachedContrastColor != COLOR_INVALID) {
                 return mCachedContrastColor;
             }
-            final int contrasted = NotificationColorUtil.resolveContrastColor(mContext, mN.color);
 
+            int color;
+            int background = mBackgroundColorHint;
+            if (mBackgroundColorHint == COLOR_INVALID) {
+                background = mContext.getColor(
+                        com.android.internal.R.color.notification_material_background_color);
+            }
+            if (mN.color == COLOR_DEFAULT) {
+                ensureColors();
+                color = mSecondaryTextColor;
+            } else {
+                color = NotificationColorUtil.resolveContrastColor(mContext, mN.color,
+                        background);
+            }
+            if (Color.alpha(color) < 255) {
+                // alpha doesn't go well for color filters, so let's blend it manually
+                color = NotificationColorUtil.compositeColors(color, background);
+            }
             mCachedContrastColorIsFor = mN.color;
-            return mCachedContrastColor = contrasted;
+            return mCachedContrastColor = color;
         }
 
         int resolveAmbientColor() {
@@ -4882,7 +4906,8 @@
             if (isColorized()) {
                 return mBackgroundColor != COLOR_INVALID ? mBackgroundColor : mN.color;
             } else {
-                return COLOR_DEFAULT;
+                return mBackgroundColorHint != COLOR_INVALID ? mBackgroundColorHint
+                        : COLOR_DEFAULT;
             }
         }
 
@@ -4913,6 +4938,17 @@
             mTextColorsAreForBackground = COLOR_INVALID;
             ensureColors();
         }
+
+        /**
+         * Sets the background color for this notification to be a different one then the default.
+         * This is mainly used to calculate contrast and won't necessarily be applied to the
+         * background.
+         *
+         * @hide
+         */
+        public void setBackgroundColorHint(int backgroundColor) {
+            mBackgroundColorHint = backgroundColor;
+        }
     }
 
     /**
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index 0265ea5..10d6a7b 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -671,22 +671,22 @@
     }
     
     /**
-     * Make this service run in the foreground, supplying the ongoing
+     * If your service is started (running through {@link Context#startService(Intent)}), then
+     * also make this service run in the foreground, supplying the ongoing
      * notification to be shown to the user while in this state.
-     * By default services are background, meaning that if the system needs to
-     * kill them to reclaim more memory (such as to display a large page in a
-     * web browser), they can be killed without too much harm.  You can set this
-     * flag if killing your service would be disruptive to the user, such as
+     * By default started services are background, meaning that their process won't be given
+     * foreground CPU scheduling (unless something else in that process is foreground) and,
+     * if the system needs to kill them to reclaim more memory (such as to display a large page in a
+     * web browser), they can be killed without too much harm.  You use
+     * {@link #startForeground} if killing your service would be disruptive to the user, such as
      * if your service is performing background music playback, so the user
      * would notice if their music stopped playing.
-     * 
-     * <p>If you need your application to run on platform versions prior to API
-     * level 5, you can use the following model to call the the older setForeground()
-     * or this modern method as appropriate:
-     * 
-     * {@sample development/samples/ApiDemos/src/com/example/android/apis/app/ForegroundService.java
-     *   foreground_compatibility}
-     * 
+     *
+     * <p>Note that calling this method does <em>not</em> put the service in the started state
+     * itself, even though the name sounds like it.  You must always call
+     * {@link #startService(Intent)} first to tell the system it should keep the service running,
+     * and then use this method to tell it to keep it running harder.</p>
+     *
      * @param id The identifier for this notification as per
      * {@link NotificationManager#notify(int, Notification)
      * NotificationManager.notify(int, Notification)}; must not be 0.
@@ -716,7 +716,9 @@
 
     /**
      * Remove this service from foreground state, allowing it to be killed if
-     * more memory is needed.
+     * more memory is needed.  This does not stop the service from running (for that
+     * you use {@link #stopSelf()} or related methods), just takes it out of the
+     * foreground state.
      *
      * @param flags additional behavior options.
      * @see #startForeground(int, Notification)
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 527314c..60b52d2 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -22,6 +22,7 @@
 import android.app.admin.IDevicePolicyManager;
 import android.app.job.IJobScheduler;
 import android.app.job.JobScheduler;
+import android.app.timezone.RulesManager;
 import android.app.trust.TrustManager;
 import android.app.usage.IStorageStatsManager;
 import android.app.usage.IUsageStatsManager;
@@ -95,7 +96,6 @@
 import android.os.BatteryManager;
 import android.os.BatteryStats;
 import android.os.Build;
-import android.os.Debug;
 import android.os.DropBoxManager;
 import android.os.HardwarePropertiesManager;
 import android.os.IBatteryPropertiesRegistrar;
@@ -118,9 +118,6 @@
 import android.os.storage.StorageManager;
 import android.print.IPrintManager;
 import android.print.PrintManager;
-import android.telephony.euicc.EuiccManager;
-import android.view.autofill.AutofillManager;
-import android.view.autofill.IAutoFillManager;
 import android.service.oemlock.IOemLockService;
 import android.service.oemlock.OemLockManager;
 import android.service.persistentdata.IPersistentDataBlockService;
@@ -130,6 +127,7 @@
 import android.telephony.CarrierConfigManager;
 import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
+import android.telephony.euicc.EuiccManager;
 import android.util.Log;
 import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
@@ -137,6 +135,8 @@
 import android.view.WindowManagerImpl;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.CaptioningManager;
+import android.view.autofill.AutofillManager;
+import android.view.autofill.IAutoFillManager;
 import android.view.inputmethod.InputMethodManager;
 import android.view.textclassifier.TextClassificationManager;
 import android.view.textservice.TextServicesManager;
@@ -872,6 +872,13 @@
                 return new VrManager(IVrManager.Stub.asInterface(b));
             }
         });
+
+        registerService(Context.TIME_ZONE_RULES_MANAGER_SERVICE, RulesManager.class,
+                new CachedServiceFetcher<RulesManager>() {
+            @Override
+            public RulesManager createService(ContextImpl ctx) {
+                return new RulesManager(ctx.getOuterContext());
+            }});
     }
 
     /**
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index 307fc91..2df011f 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -39,7 +39,7 @@
     }
 
     @Override
-    public void onPinnedActivityRestartAttempt() throws RemoteException {
+    public void onPinnedActivityRestartAttempt(boolean clearedTask) throws RemoteException {
     }
 
     @Override
diff --git a/core/java/android/app/CompatibilityDisplayProperties.aidl b/core/java/android/app/Vr2dDisplayProperties.aidl
similarity index 93%
rename from core/java/android/app/CompatibilityDisplayProperties.aidl
rename to core/java/android/app/Vr2dDisplayProperties.aidl
index 626a63e..1e04943 100644
--- a/core/java/android/app/CompatibilityDisplayProperties.aidl
+++ b/core/java/android/app/Vr2dDisplayProperties.aidl
@@ -17,4 +17,4 @@
 package android.app;
 
 /** @hide */
-parcelable CompatibilityDisplayProperties;
+parcelable Vr2dDisplayProperties;
diff --git a/core/java/android/app/CompatibilityDisplayProperties.java b/core/java/android/app/Vr2dDisplayProperties.java
similarity index 75%
rename from core/java/android/app/CompatibilityDisplayProperties.java
rename to core/java/android/app/Vr2dDisplayProperties.java
index 9a9bc2c..a608bb0 100644
--- a/core/java/android/app/CompatibilityDisplayProperties.java
+++ b/core/java/android/app/Vr2dDisplayProperties.java
@@ -27,7 +27,7 @@
  *
  * @hide
  */
-public class CompatibilityDisplayProperties implements Parcelable {
+public class Vr2dDisplayProperties implements Parcelable {
 
    /**
     * The actual width, height and dpi.
@@ -36,7 +36,7 @@
     private final int mHeight;
     private final int mDpi;
 
-    public CompatibilityDisplayProperties(int width, int height, int dpi) {
+    public Vr2dDisplayProperties(int width, int height, int dpi) {
         mWidth = width;
         mHeight = height;
         mDpi = dpi;
@@ -52,7 +52,7 @@
 
     @Override
     public String toString() {
-        return "CompatibilityDisplayProperties{" +
+        return "Vr2dDisplayProperties{" +
                 "mWidth=" + mWidth +
                 ", mHeight=" + mHeight +
                 ", mDpi=" + mDpi +
@@ -64,7 +64,7 @@
         if (this == o) return true;
         if (o == null || getClass() != o.getClass()) return false;
 
-        CompatibilityDisplayProperties that = (CompatibilityDisplayProperties) o;
+        Vr2dDisplayProperties that = (Vr2dDisplayProperties) o;
 
         if (getWidth() != that.getWidth()) return false;
         if (getHeight() != that.getHeight()) return false;
@@ -83,27 +83,27 @@
         dest.writeInt(mDpi);
     }
 
-    public static final Parcelable.Creator<CompatibilityDisplayProperties> CREATOR
-            = new Parcelable.Creator<CompatibilityDisplayProperties>() {
+    public static final Parcelable.Creator<Vr2dDisplayProperties> CREATOR
+            = new Parcelable.Creator<Vr2dDisplayProperties>() {
         @Override
-        public CompatibilityDisplayProperties createFromParcel(Parcel source) {
-            return new CompatibilityDisplayProperties(source);
+        public Vr2dDisplayProperties createFromParcel(Parcel source) {
+            return new Vr2dDisplayProperties(source);
         }
 
         @Override
-        public CompatibilityDisplayProperties[] newArray(int size) {
-            return new CompatibilityDisplayProperties[size];
+        public Vr2dDisplayProperties[] newArray(int size) {
+            return new Vr2dDisplayProperties[size];
         }
     };
 
-    private CompatibilityDisplayProperties(Parcel source) {
+    private Vr2dDisplayProperties(Parcel source) {
         mWidth = source.readInt();
         mHeight = source.readInt();
         mDpi = source.readInt();
     }
 
     public void dump(PrintWriter pw, String prefix) {
-        pw.println(prefix + "CompatibilityDisplayProperties:");
+        pw.println(prefix + "Vr2dDisplayProperties:");
         pw.println(prefix + "  width=" + mWidth);
         pw.println(prefix + "  height=" + mHeight);
         pw.println(prefix + "  dpi=" + mDpi);
diff --git a/core/java/android/app/VrManager.java b/core/java/android/app/VrManager.java
index 878c8c3..8014eca 100644
--- a/core/java/android/app/VrManager.java
+++ b/core/java/android/app/VrManager.java
@@ -6,8 +6,6 @@
 import android.os.RemoteException;
 import android.service.vr.IVrManager;
 
-import java.io.FileDescriptor;
-
 /**
  * Used to control aspects of a devices Virtual Reality (VR) capabilities.
  * <p>
@@ -45,48 +43,20 @@
     }
 
     /**
-     * Sets the resolution and DPI of the compatibility virtual display used to display 2D
+     * Sets the resolution and DPI of the vr2d virtual display used to display 2D
      * applications in VR mode.
      *
      * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
      *
-     * @param {@link android.app.CompatibilityDisplayProperties} properties to be set to the
-     * virtual display for 2D applications in VR mode.
+     * @param vr2dDisplayProp properties to be set to the virtual display for
+     * 2D applications in VR mode.
      *
      * {@hide}
      */
-    public void setCompatibilityDisplayProperties(
-            CompatibilityDisplayProperties compatDisplayProp) {
+    public void setVr2dDisplayProperties(
+            Vr2dDisplayProperties vr2dDisplayProp) {
         try {
-            mService.setCompatibilityDisplayProperties(compatDisplayProp);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Initiate connection for system controller data.
-     *
-     * @param fd Controller data file descriptor.
-     *
-     * {@hide}
-     */
-    public void connectController(FileDescriptor fd) {
-        try {
-            mService.connectController(fd);
-        } catch (RemoteException e) {
-            e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
-     * Sever connection for system controller data.
-     *
-     * {@hide}
-     */
-    public void disconnectController() {
-        try {
-            mService.disconnectController();
+            mService.setVr2dDisplayProperties(vr2dDisplayProp);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 3353530..1994206 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -18,6 +18,7 @@
 import android.os.PooledStringWriter;
 import android.os.RemoteException;
 import android.os.SystemClock;
+import android.service.autofill.FillContext;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
@@ -1103,6 +1104,9 @@
          * Returns the transformation that has been applied to this view, such as a translation
          * or scaling.  The returned Matrix object is owned by ViewNode; do not modify it.
          * Returns null if there is no transformation applied to the view.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public Matrix getTransformation() {
             return mMatrix;
@@ -1112,6 +1116,9 @@
          * Returns the visual elevation of the view, used for shadowing and other visual
          * characterstics, as set by {@link ViewStructure#setElevation
          * ViewStructure.setElevation(float)}.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public float getElevation() {
             return mElevation;
@@ -1121,6 +1128,9 @@
          * Returns the alpha transformation of the view, used to reduce the overall opacity
          * of the view's contents, as set by {@link ViewStructure#setAlpha
          * ViewStructure.setAlpha(float)}.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public float getAlpha() {
             return mAlpha;
@@ -1289,6 +1299,9 @@
 
         /**
          * If {@link #getText()} is non-null, this is where the current selection starts.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int getTextSelectionStart() {
             return mText != null ? mText.mTextSelectionStart : -1;
@@ -1298,6 +1311,9 @@
          * If {@link #getText()} is non-null, this is where the current selection starts.
          * If there is no selection, returns the same value as {@link #getTextSelectionStart()},
          * indicating the cursor position.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int getTextSelectionEnd() {
             return mText != null ? mText.mTextSelectionEnd : -1;
@@ -1319,6 +1335,9 @@
          * If there is no text background color, {@link #TEXT_COLOR_UNDEFINED} is returned.
          * Note that the text may also contain style spans that modify the color of specific
          * parts of the text.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int getTextBackgroundColor() {
             return mText != null ? mText.mTextBackgroundColor : TEXT_COLOR_UNDEFINED;
@@ -1329,6 +1348,9 @@
          * with it.
          * Note that the text may also contain style spans that modify the size of specific
          * parts of the text.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public float getTextSize() {
             return mText != null ? mText.mTextSize : 0;
@@ -1341,6 +1363,9 @@
          * {@link #TEXT_STYLE_UNDERLINE}.
          * Note that the text may also contain style spans that modify the style of specific
          * parts of the text.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int getTextStyle() {
             return mText != null ? mText.mTextStyle : 0;
@@ -1351,6 +1376,9 @@
          * in the array is a formatted line of text, and the value it contains is the offset
          * into the text string where that line starts.  May return null if there is no line
          * information.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int[] getTextLineCharOffsets() {
             return mText != null ? mText.mLineCharOffsets : null;
@@ -1361,6 +1389,9 @@
          * in the array is a formatted line of text, and the value it contains is the baseline
          * where that text appears in the view.  May return null if there is no line
          * information.
+         *
+         * <p>It's only relevant when the {@link AssistStructure} is used for Assist purposes,
+         * not for Autofill purposes.
          */
         public int[] getTextLineBaselines() {
             return mText != null ? mText.mLineBaselines : null;
@@ -1559,14 +1590,14 @@
         @Override
         public void setText(CharSequence text) {
             ViewNodeText t = getNodeText();
-            t.mText = text;
+            t.mText = TextUtils.trimNoCopySpans(text);
             t.mTextSelectionStart = t.mTextSelectionEnd = -1;
         }
 
         @Override
         public void setText(CharSequence text, int selectionStart, int selectionEnd) {
             ViewNodeText t = getNodeText();
-            t.mText = text;
+            t.mText = TextUtils.trimNoCopySpans(text);
             t.mTextSelectionStart = selectionStart;
             t.mTextSelectionEnd = selectionEnd;
         }
@@ -1737,13 +1768,6 @@
         }
 
         @Override
-        public void setUrl(String url) {
-            if (url == null) return;
-
-            setWebDomain(url);
-        }
-
-        @Override
         public void setWebDomain(@Nullable String domain) {
             if (domain == null) {
                 mNode.mWebDomain = null;
diff --git a/core/java/android/app/timezone/Callback.java b/core/java/android/app/timezone/Callback.java
new file mode 100644
index 0000000..b51e5ba
--- /dev/null
+++ b/core/java/android/app/timezone/Callback.java
@@ -0,0 +1,76 @@
+/*
+ * 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 android.app.timezone;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Callback interface for receiving information about an async time zone operation.
+ * The methods will be called on your application's main thread.
+ *
+ * @hide
+ */
+// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
+public abstract class Callback {
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SUCCESS, ERROR_UNKNOWN_FAILURE, ERROR_INSTALL_BAD_DISTRO_STRUCTURE,
+        ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION, ERROR_INSTALL_RULES_TOO_OLD,
+        ERROR_INSTALL_VALIDATION_ERROR})
+    public @interface AsyncResultCode {}
+
+    /**
+     * Indicates that an operation succeeded.
+     */
+    public static final int SUCCESS = 0;
+
+    /**
+     * Indicates an install / uninstall did not fully succeed for an unknown reason.
+     */
+    public static final int ERROR_UNKNOWN_FAILURE = 1;
+
+    /**
+     * Indicates an install failed because of a structural issue with the provided distro,
+     * e.g. it wasn't in the right format or the contents were structured incorrectly.
+     */
+    public static final int ERROR_INSTALL_BAD_DISTRO_STRUCTURE = 2;
+
+    /**
+     * Indicates an install failed because of a versioning issue with the provided distro,
+     * e.g. it was created for a different version of Android.
+     */
+    public static final int ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION = 3;
+
+    /**
+     * Indicates an install failed because the rules provided are too old for the device,
+     * e.g. the Android device shipped with a newer rules version.
+     */
+    public static final int ERROR_INSTALL_RULES_TOO_OLD = 4;
+
+    /**
+     * Indicates an install failed because the distro contents failed validation.
+     */
+    public static final int ERROR_INSTALL_VALIDATION_ERROR = 5;
+
+    /**
+     * Reports the result of an async time zone operation.
+     */
+    public abstract void onFinished(@AsyncResultCode int status);
+}
diff --git a/core/java/android/app/timezone/DistroFormatVersion.java b/core/java/android/app/timezone/DistroFormatVersion.java
new file mode 100644
index 0000000..e879e8f
--- /dev/null
+++ b/core/java/android/app/timezone/DistroFormatVersion.java
@@ -0,0 +1,120 @@
+/*
+ * 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 android.app.timezone;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Versioning information about a distro's format or a device's supported format.
+ *
+ * <p>The following properties are included:
+ * <dl>
+ *     <dt>majorVersion</dt>
+ *     <dd>the major distro format version. Major versions differences are not compatible - e.g.
+ *     2 is not compatible with 1 or 3.</dd>
+ *     <dt>minorVersion</dt>
+ *     <dd>the minor distro format version. Minor versions should be backwards compatible iff the
+ *     major versions match exactly, i.e. version 2.2 will be compatible with 2.1 devices but not
+ *     2.3 devices.</dd>
+ * </dl>
+ *
+ * @hide
+ */
+// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
+public final class DistroFormatVersion implements Parcelable {
+
+    private final int mMajorVersion;
+    private final int mMinorVersion;
+
+    public DistroFormatVersion(int majorVersion, int minorVersion) {
+        mMajorVersion = Utils.validateVersion("major", majorVersion);
+        mMinorVersion = Utils.validateVersion("minor", minorVersion);
+    }
+
+    public static final Creator<DistroFormatVersion> CREATOR = new Creator<DistroFormatVersion>() {
+        public DistroFormatVersion createFromParcel(Parcel in) {
+            int majorVersion = in.readInt();
+            int minorVersion = in.readInt();
+            return new DistroFormatVersion(majorVersion, minorVersion);
+        }
+
+        public DistroFormatVersion[] newArray(int size) {
+            return new DistroFormatVersion[size];
+        }
+    };
+
+    public int getMajorVersion() {
+        return mMajorVersion;
+    }
+
+    public int getMinorVersion() {
+        return mMinorVersion;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(mMajorVersion);
+        out.writeInt(mMinorVersion);
+    }
+
+    /**
+     * If this object describes a device's supported version and the parameter describes a distro's
+     * version, this method returns whether the device would accept the distro.
+     */
+    public boolean supports(DistroFormatVersion distroFormatVersion) {
+        return mMajorVersion == distroFormatVersion.mMajorVersion
+                && mMinorVersion <= distroFormatVersion.mMinorVersion;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        DistroFormatVersion that = (DistroFormatVersion) o;
+
+        if (mMajorVersion != that.mMajorVersion) {
+            return false;
+        }
+        return mMinorVersion == that.mMinorVersion;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mMajorVersion;
+        result = 31 * result + mMinorVersion;
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "DistroFormatVersion{"
+                + "mMajorVersion=" + mMajorVersion
+                + ", mMinorVersion=" + mMinorVersion
+                + '}';
+    }
+}
diff --git a/core/java/android/app/timezone/DistroRulesVersion.java b/core/java/android/app/timezone/DistroRulesVersion.java
new file mode 100644
index 0000000..5503ce1
--- /dev/null
+++ b/core/java/android/app/timezone/DistroRulesVersion.java
@@ -0,0 +1,128 @@
+/*
+ * 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 android.app.timezone;
+
+import static android.app.timezone.Utils.validateRulesVersion;
+import static android.app.timezone.Utils.validateVersion;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Versioning information about a set of time zone rules.
+ *
+ * <p>The following properties are included:
+ * <dl>
+ *     <dt>rulesVersion</dt>
+ *     <dd>the IANA rules version. e.g. "2017a"</dd>
+ *     <dt>revision</dt>
+ *     <dd>the revision for the rules. Allows there to be several revisions for a given IANA rules
+ *     release. Numerically higher is newer.</dd>
+ * </dl>
+ *
+ * @hide
+ */
+// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
+public final class DistroRulesVersion implements Parcelable {
+
+    private final String mRulesVersion;
+    private final int mRevision;
+
+    public DistroRulesVersion(String rulesVersion, int revision) {
+        mRulesVersion = validateRulesVersion("rulesVersion", rulesVersion);
+        mRevision = validateVersion("revision", revision);
+    }
+
+    public static final Creator<DistroRulesVersion> CREATOR = new Creator<DistroRulesVersion>() {
+        public DistroRulesVersion createFromParcel(Parcel in) {
+            String rulesVersion = in.readString();
+            int revision = in.readInt();
+            return new DistroRulesVersion(rulesVersion, revision);
+        }
+
+        public DistroRulesVersion[] newArray(int size) {
+            return new DistroRulesVersion[size];
+        }
+    };
+
+    public String getRulesVersion() {
+        return mRulesVersion;
+    }
+
+    public int getRevision() {
+        return mRevision;
+    }
+
+    /**
+     * Returns true if this DistroRulesVersion is older than the one supplied. It returns false if
+     * it is the same or newer. This method compares the {@code rulesVersion} and the
+     * {@code revision}.
+     */
+    public boolean isOlderThan(DistroRulesVersion distroRulesVersion) {
+        int rulesComparison = mRulesVersion.compareTo(distroRulesVersion.mRulesVersion);
+        if (rulesComparison < 0) {
+            return true;
+        }
+        if (rulesComparison > 0) {
+            return false;
+        }
+        return mRevision < distroRulesVersion.mRevision;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mRulesVersion);
+        out.writeInt(mRevision);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        DistroRulesVersion that = (DistroRulesVersion) o;
+
+        if (mRevision != that.mRevision) {
+            return false;
+        }
+        return mRulesVersion.equals(that.mRulesVersion);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mRulesVersion.hashCode();
+        result = 31 * result + mRevision;
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "DistroRulesVersion{"
+                + "mRulesVersion='" + mRulesVersion + '\''
+                + ", mRevision='" + mRevision + '\''
+                + '}';
+    }
+}
diff --git a/core/java/android/app/CompatibilityDisplayProperties.aidl b/core/java/android/app/timezone/ICallback.aidl
similarity index 70%
copy from core/java/android/app/CompatibilityDisplayProperties.aidl
copy to core/java/android/app/timezone/ICallback.aidl
index 626a63e..519ef1a 100644
--- a/core/java/android/app/CompatibilityDisplayProperties.aidl
+++ b/core/java/android/app/timezone/ICallback.aidl
@@ -14,7 +14,14 @@
  * limitations under the License.
  */
 
-package android.app;
+package android.app.timezone;
 
-/** @hide */
-parcelable CompatibilityDisplayProperties;
+/**
+ * Callback interface for a timezone updater to receive information about the success or failure of
+ * an installation/uninstallation attempt.
+ *
+ * {@hide}
+ */
+oneway interface ICallback {
+    void onFinished(int error);
+}
\ No newline at end of file
diff --git a/core/java/android/app/timezone/IRulesManager.aidl b/core/java/android/app/timezone/IRulesManager.aidl
new file mode 100644
index 0000000..40f3fd2
--- /dev/null
+++ b/core/java/android/app/timezone/IRulesManager.aidl
@@ -0,0 +1,84 @@
+/*
+ * 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 android.app.timezone;
+
+import android.app.timezone.ICallback;
+import android.app.timezone.RulesState;
+import android.os.ParcelFileDescriptor;
+
+ /**
+  * Interface to the TimeZone Rules Manager Service.
+  *
+  * <p>This interface is only intended for system apps to call. They should use the
+  * {@link android.app.timezone.RulesManager} class rather than going through this
+  * Binder interface directly. See {@link android.app.timezone.RulesManager} for more complete
+  * documentation.
+  *
+  * {@hide}
+  */
+interface IRulesManager {
+
+    /**
+     * Returns information about the current time zone rules state such as the IANA version of
+     * the system and any currently installed distro. This method is intended to allow clients to
+     * determine if the current state can be improved; for example by passing the information to a
+     * server that may provide a new distro for download.
+     */
+    RulesState getRulesState();
+
+    /**
+     * Requests installation of the supplied distro. The distro must have been checked for integrity
+     * by the caller or have been received via a trusted mechanism.
+     *
+     * @param distroFileDescriptor the file descriptor for the distro
+     * @param checkToken an optional token provided if the install was triggered in response to a
+     *     {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
+     * @param callback the {@link ICallback} to receive callbacks related to the
+     *     installation
+     * @return zero if the installation will be attempted; nonzero on error
+     */
+    int requestInstall(in ParcelFileDescriptor distroFileDescriptor, in byte[] checkToken,
+            ICallback callback);
+
+    /**
+     * Requests uninstallation of the currently installed distro (leaving the device with no
+     * distro installed).
+     *
+     * @param checkToken an optional token provided if the uninstall was triggered in response to a
+     *     {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
+     * @param callback the {@link ICallback} to receive callbacks related to the
+     *     uninstall
+     * @return zero if the uninstallation will be attempted; nonzero on error
+     */
+    int requestUninstall(in byte[] checkToken, ICallback callback);
+
+    /**
+     * Requests the system does not modify the currently installed time zone distro, if any. This
+     * method records the fact that a time zone check operation triggered by the system is now
+     * complete and there was nothing to do. The token passed should be the one presented when the
+     * check was triggered.
+     *
+     * <p>Note: Passing {@code success == false} may result in more checks being triggered. Clients
+     * should be careful not to pass false if the failure is unlikely to resolve by itself.
+     *
+     * @param checkToken an optional token provided if the install was triggered in response to a
+     *     {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
+     * @param success true if the check was successful, false if it was not successful but may
+     *     succeed if it is retried
+     */
+    void requestNothing(in byte[] token, boolean success);
+}
diff --git a/core/java/android/app/timezone/RulesManager.java b/core/java/android/app/timezone/RulesManager.java
new file mode 100644
index 0000000..649d894
--- /dev/null
+++ b/core/java/android/app/timezone/RulesManager.java
@@ -0,0 +1,212 @@
+/*
+ * 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 android.app.timezone;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.os.Handler;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+import java.io.IOException;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+
+/**
+ * The interface through which a time zone update application interacts with the Android system
+ * to handle time zone rule updates.
+ *
+ * <p>This interface is intended for use with the default APK-based time zone rules update
+ * application but it can also be used by OEMs if that mechanism is turned off using configuration.
+ * All callers must possess the {@link android.Manifest.permission#UPDATE_TIME_ZONE_RULES} system
+ * permission.
+ *
+ * <p>When using the default mechanism, when properly configured the Android system will send a
+ * {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent with a
+ * {@link RulesUpdaterContract#EXTRA_CHECK_TOKEN} extra to the time zone rules updater application
+ * when it detects that it or the OEM's APK containing time zone rules data has been modified. The
+ * updater application is then responsible for calling one of
+ * {@link #requestInstall(ParcelFileDescriptor, byte[], Callback)},
+ * {@link #requestUninstall(byte[], Callback)} or
+ * {@link #requestNothing(byte[], boolean)}, indicating, respectively, whether a new time zone rules
+ * distro should be installed, the current distro should be uninstalled, or there is nothing to do
+ * (or that the correct operation could not be determined due to an error). In each case the updater
+ * must pass the {@link RulesUpdaterContract#EXTRA_CHECK_TOKEN} value it received from the intent
+ * back so the system in the {@code checkToken} parameter.
+ *
+ * <p>If OEMs want to handle their own time zone rules updates, perhaps via a server-side component
+ * rather than an APK, then they should disable the default triggering mechanism in config and are
+ * responsible for triggering their own update checks / installs / uninstalls. In this case the
+ * "check token" parameter can be left null and there is never any need to call
+ * {@link #requestNothing(byte[], boolean)}.
+ *
+ * <p>OEMs should not mix the default mechanism and their own as this could lead to conflicts and
+ * unnecessary checks being triggered.
+ *
+ * <p>Applications obtain this using {@link android.app.Activity#getSystemService(String)} with
+ * {@link Context#TIME_ZONE_RULES_MANAGER_SERVICE}.
+ * @hide
+ */
+// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
+public final class RulesManager {
+    private static final String TAG = "timezone.RulesManager";
+    private static final boolean DEBUG = false;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SUCCESS, ERROR_UNKNOWN_FAILURE, ERROR_OPERATION_IN_PROGRESS})
+    public @interface ResultCode {}
+
+    /**
+     * Indicates that an operation succeeded.
+     */
+    public static final int SUCCESS = 0;
+
+    /**
+     * Indicates that an install/uninstall cannot be initiated because there is one already in
+     * progress.
+     */
+    public static final int ERROR_OPERATION_IN_PROGRESS = 1;
+
+    /**
+     * Indicates an install / uninstall did not fully succeed for an unknown reason.
+     */
+    public static final int ERROR_UNKNOWN_FAILURE = 2;
+
+    private final Context mContext;
+    private final IRulesManager mIRulesManager;
+
+    public RulesManager(Context context) {
+        mContext = context;
+        mIRulesManager = IRulesManager.Stub.asInterface(
+                ServiceManager.getService(Context.TIME_ZONE_RULES_MANAGER_SERVICE));
+    }
+
+    /**
+     * Returns information about the current time zone rules state such as the IANA version of
+     * the system and any currently installed distro. This method is intended to allow clients to
+     * determine if the current state can be improved; for example by passing the information to a
+     * server that may provide a new distro for download.
+     */
+    public RulesState getRulesState() {
+        try {
+            logDebug("sIRulesManager.getRulesState()");
+            RulesState rulesState = mIRulesManager.getRulesState();
+            logDebug("sIRulesManager.getRulesState() returned " + rulesState);
+            return rulesState;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Requests installation of the supplied distro. The distro must have been checked for integrity
+     * by the caller or have been received via a trusted mechanism.
+     *
+     * @param distroFileDescriptor the file descriptor for the distro
+     * @param checkToken an optional token provided if the install was triggered in response to a
+     *     {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
+     * @param callback the {@link Callback} to receive callbacks related to the installation
+     * @return {@link #SUCCESS} if the installation will be attempted
+     */
+    @ResultCode
+    public int requestInstall(
+            ParcelFileDescriptor distroFileDescriptor, byte[] checkToken, Callback callback)
+            throws IOException {
+
+        ICallback iCallback = new CallbackWrapper(mContext, callback);
+        try {
+            logDebug("sIRulesManager.requestInstall()");
+            return mIRulesManager.requestInstall(distroFileDescriptor, checkToken, iCallback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Requests uninstallation of the currently installed distro (leaving the device with no
+     * distro installed).
+     *
+     * @param checkToken an optional token provided if the uninstall was triggered in response to a
+     *     {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
+     * @param callback the {@link Callback} to receive callbacks related to the uninstall
+     * @return {@link #SUCCESS} if the uninstallation will be attempted
+     */
+    @ResultCode
+    public int requestUninstall(byte[] checkToken, Callback callback) {
+        ICallback iCallback = new CallbackWrapper(mContext, callback);
+        try {
+            logDebug("sIRulesManager.requestUninstall()");
+            return mIRulesManager.requestUninstall(checkToken, iCallback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /*
+     * We wrap incoming binder calls with a private class implementation that
+     * redirects them into main-thread actions.  This serializes the backup
+     * progress callbacks nicely within the usual main-thread lifecycle pattern.
+     */
+    private class CallbackWrapper extends ICallback.Stub {
+        final Handler mHandler;
+        final Callback mCallback;
+
+        CallbackWrapper(Context context, Callback callback) {
+            mCallback = callback;
+            mHandler = new Handler(context.getMainLooper());
+        }
+
+        // Binder calls into this object just enqueue on the main-thread handler
+        @Override
+        public void onFinished(int status) {
+            logDebug("mCallback.onFinished(status), status=" + status);
+            mHandler.post(() -> mCallback.onFinished(status));
+        }
+    }
+
+    /**
+     * Requests the system does not modify the currently installed time zone distro, if any. This
+     * method records the fact that a time zone check operation triggered by the system is now
+     * complete and there was nothing to do. The token passed should be the one presented when the
+     * check was triggered.
+     *
+     * <p>Note: Passing {@code success == false} may result in more checks being triggered. Clients
+     * should be careful not to pass false if the failure is unlikely to resolve by itself.
+     *
+     * @param checkToken an optional token provided if the install was triggered in response to a
+     *     {@link RulesUpdaterContract#ACTION_TRIGGER_RULES_UPDATE_CHECK} intent
+     * @param succeeded true if the check was successful, false if it was not successful but may
+     *     succeed if it is retried
+     */
+    public void requestNothing(byte[] checkToken, boolean succeeded) {
+        try {
+            logDebug("sIRulesManager.requestNothing() with token=" + Arrays.toString(checkToken));
+            mIRulesManager.requestNothing(checkToken, succeeded);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    static void logDebug(String msg) {
+        if (DEBUG) {
+            Log.v(TAG, msg);
+        }
+    }
+}
diff --git a/core/java/android/app/CompatibilityDisplayProperties.aidl b/core/java/android/app/timezone/RulesState.aidl
similarity index 88%
copy from core/java/android/app/CompatibilityDisplayProperties.aidl
copy to core/java/android/app/timezone/RulesState.aidl
index 626a63e..f789120 100644
--- a/core/java/android/app/CompatibilityDisplayProperties.aidl
+++ b/core/java/android/app/timezone/RulesState.aidl
@@ -14,7 +14,4 @@
  * limitations under the License.
  */
 
-package android.app;
-
-/** @hide */
-parcelable CompatibilityDisplayProperties;
+parcelable RulesState;
\ No newline at end of file
diff --git a/core/java/android/app/timezone/RulesState.java b/core/java/android/app/timezone/RulesState.java
new file mode 100644
index 0000000..33f4e80
--- /dev/null
+++ b/core/java/android/app/timezone/RulesState.java
@@ -0,0 +1,319 @@
+/*
+ * 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 android.app.timezone;
+
+import static android.app.timezone.Utils.validateConditionalNull;
+import static android.app.timezone.Utils.validateNotNull;
+import static android.app.timezone.Utils.validateRulesVersion;
+
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Description of the state of time zone rules on a device.
+ *
+ * <p>The following properties are included:
+ * <dl>
+ *     <dt>systemRulesVersion</dt>
+ *     <dd>the IANA rules version that shipped with the OS. Always present. e.g. "2017a".</dd>
+ *     <dt>distroFormatVersionSupported</dt>
+ *     <dd>the distro format version supported by this device. Always present.</dd>
+ *     <dt>operationInProgress</dt>
+ *     <dd>{@code true} if there is an install / uninstall operation currently happening.</dd>
+ *     <dt>stagedOperationType</dt>
+ *     <dd>one of {@link #STAGED_OPERATION_UNKNOWN}, {@link #STAGED_OPERATION_NONE},
+ *     {@link #STAGED_OPERATION_UNINSTALL} and {@link #STAGED_OPERATION_INSTALL} indicating whether
+ *     there is a currently staged time zone distro operation. {@link #STAGED_OPERATION_UNKNOWN} is
+ *     used when {@link #isOperationInProgress()} is {@code true}. Staged operations currently
+ *     require a reboot to become active.</dd>
+ *     <dt>stagedDistroRulesVersion</dt>
+ *     <dd>[present if distroStagedState == STAGED_STATE_INSTALL], the rules version of the distro
+ *     currently staged for installation.</dd>
+ *     <dt>distroStatus</dt>
+ *     <dd>{@link #DISTRO_STATUS_INSTALLED} if there is a time zone distro installed and active,
+ *     {@link #DISTRO_STATUS_NONE} if there is no active installed distro.
+ *     {@link #DISTRO_STATUS_UNKNOWN} is used when {@link #isOperationInProgress()} is {@code true}.
+ *     </dd>
+ *     <dt>installedDistroRulesVersion</dt>
+ *     <dd>[present if distroStatus == {@link #DISTRO_STATUS_INSTALLED}], the rules version of the
+ *     installed and active distro.</dd>
+ * </dl>
+ *
+ * @hide
+ */
+// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
+public final class RulesState implements Parcelable {
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            STAGED_OPERATION_UNKNOWN,
+            STAGED_OPERATION_NONE,
+            STAGED_OPERATION_UNINSTALL,
+            STAGED_OPERATION_INSTALL })
+    private @interface StagedOperationType {}
+
+    /** Staged state could not be determined. */
+    public static final int STAGED_OPERATION_UNKNOWN = 0;
+    /** Nothing is staged. */
+    public static final int STAGED_OPERATION_NONE = 1;
+    /** An uninstall is staged. */
+    public static final int STAGED_OPERATION_UNINSTALL = 2;
+    /** An install is staged. */
+    public static final int STAGED_OPERATION_INSTALL = 3;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            DISTRO_STATUS_UNKNOWN,
+            DISTRO_STATUS_NONE,
+            DISTRO_STATUS_INSTALLED })
+    private @interface DistroStatus {}
+
+    /** The current distro status could not be determined. */
+    public static final int DISTRO_STATUS_UNKNOWN = 0;
+    /** There is no active installed time zone distro. */
+    public static final int DISTRO_STATUS_NONE = 1;
+    /** The is an active, installed time zone distro. */
+    public static final int DISTRO_STATUS_INSTALLED = 2;
+
+    private static final byte BYTE_FALSE = 0;
+    private static final byte BYTE_TRUE = 1;
+
+    private final String mSystemRulesVersion;
+    private final DistroFormatVersion mDistroFormatVersionSupported;
+    private final boolean mOperationInProgress;
+    @StagedOperationType private final int mStagedOperationType;
+    @Nullable private final DistroRulesVersion mStagedDistroRulesVersion;
+    @DistroStatus private final int mDistroStatus;
+    @Nullable private final DistroRulesVersion mInstalledDistroRulesVersion;
+
+    public RulesState(String systemRulesVersion, DistroFormatVersion distroFormatVersionSupported,
+            boolean operationInProgress,
+            @StagedOperationType int stagedOperationType,
+            @Nullable DistroRulesVersion stagedDistroRulesVersion,
+            @DistroStatus int distroStatus,
+            @Nullable DistroRulesVersion installedDistroRulesVersion) {
+        this.mSystemRulesVersion = validateRulesVersion("systemRulesVersion", systemRulesVersion);
+        this.mDistroFormatVersionSupported =
+                validateNotNull("distroFormatVersionSupported", distroFormatVersionSupported);
+        this.mOperationInProgress = operationInProgress;
+
+        if (operationInProgress && stagedOperationType != STAGED_OPERATION_UNKNOWN) {
+            throw new IllegalArgumentException(
+                    "stagedOperationType != STAGED_OPERATION_UNKNOWN");
+        }
+        this.mStagedOperationType = validateStagedOperation(stagedOperationType);
+        this.mStagedDistroRulesVersion = validateConditionalNull(
+                mStagedOperationType == STAGED_OPERATION_INSTALL /* requireNotNull */,
+                "stagedDistroRulesVersion", stagedDistroRulesVersion);
+
+        if (operationInProgress && distroStatus != DISTRO_STATUS_UNKNOWN) {
+            throw new IllegalArgumentException("distroInstalled != DISTRO_STATUS_UNKNOWN");
+        }
+        this.mDistroStatus = validateDistroStatus(distroStatus);
+        this.mInstalledDistroRulesVersion = validateConditionalNull(
+                mDistroStatus == DISTRO_STATUS_INSTALLED/* requireNotNull */,
+                "installedDistroRulesVersion", installedDistroRulesVersion);
+    }
+
+    public String getSystemRulesVersion() {
+        return mSystemRulesVersion;
+    }
+
+    public boolean isOperationInProgress() {
+        return mOperationInProgress;
+    }
+
+    public @StagedOperationType int getStagedOperationType() {
+        return mStagedOperationType;
+    }
+
+    /**
+     * Returns the staged rules version when {@link #getStagedOperationType()} is
+     * {@link #STAGED_OPERATION_INSTALL}.
+     */
+    public @Nullable DistroRulesVersion getStagedDistroRulesVersion() {
+        return mStagedDistroRulesVersion;
+    }
+
+    public @DistroStatus int getDistroStatus() {
+        return mDistroStatus;
+    }
+
+    /**
+     * Returns the installed rules version when {@link #getDistroStatus()} is
+     * {@link #DISTRO_STATUS_INSTALLED}.
+     */
+    public @Nullable DistroRulesVersion getInstalledDistroRulesVersion() {
+        return mInstalledDistroRulesVersion;
+    }
+
+    /**
+     * Returns true if a distro in the specified format is supported on this device.
+     */
+    public boolean isDistroFormatVersionSupported(DistroFormatVersion distroFormatVersion) {
+        return mDistroFormatVersionSupported.supports(distroFormatVersion);
+    }
+
+    /**
+     * Returns true if the distro IANA rules version supplied is newer or the same as the version in
+     * the system image data files.
+     */
+    public boolean isSystemVersionOlderThan(DistroRulesVersion distroRulesVersion) {
+        return mSystemRulesVersion.compareTo(distroRulesVersion.getRulesVersion()) < 0;
+    }
+
+    public boolean isDistroInstalled() {
+        return mDistroStatus == DISTRO_STATUS_INSTALLED;
+    }
+
+    /**
+     * Returns true if the rules version supplied is newer than the one currently installed. If
+     * there is no installed distro this method throws IllegalStateException.
+     */
+    public boolean isInstalledDistroOlderThan(DistroRulesVersion distroRulesVersion) {
+        if (mOperationInProgress) {
+            throw new IllegalStateException("Distro state not known: operation in progress.");
+        }
+        if (!isDistroInstalled()) {
+            throw new IllegalStateException("No distro installed.");
+        }
+        return mInstalledDistroRulesVersion.isOlderThan(distroRulesVersion);
+    }
+
+    public static final Parcelable.Creator<RulesState> CREATOR =
+            new Parcelable.Creator<RulesState>() {
+        public RulesState createFromParcel(Parcel in) {
+            return RulesState.createFromParcel(in);
+        }
+
+        public RulesState[] newArray(int size) {
+            return new RulesState[size];
+        }
+    };
+
+    private static RulesState createFromParcel(Parcel in) {
+        String systemRulesVersion = in.readString();
+        DistroFormatVersion distroFormatVersionSupported = in.readParcelable(null);
+        boolean operationInProgress = in.readByte() == BYTE_TRUE;
+        int distroStagedState = in.readByte();
+        DistroRulesVersion stagedDistroRulesVersion = in.readParcelable(null);
+        int installedDistroStatus = in.readByte();
+        DistroRulesVersion installedDistroRulesVersion = in.readParcelable(null);
+        return new RulesState(systemRulesVersion, distroFormatVersionSupported, operationInProgress,
+                distroStagedState, stagedDistroRulesVersion,
+                installedDistroStatus, installedDistroRulesVersion);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mSystemRulesVersion);
+        out.writeParcelable(mDistroFormatVersionSupported, 0);
+        out.writeByte(mOperationInProgress ? BYTE_TRUE : BYTE_FALSE);
+        out.writeByte((byte) mStagedOperationType);
+        out.writeParcelable(mStagedDistroRulesVersion, 0);
+        out.writeByte((byte) mDistroStatus);
+        out.writeParcelable(mInstalledDistroRulesVersion, 0);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        RulesState that = (RulesState) o;
+
+        if (mOperationInProgress != that.mOperationInProgress) {
+            return false;
+        }
+        if (mStagedOperationType != that.mStagedOperationType) {
+            return false;
+        }
+        if (mDistroStatus != that.mDistroStatus) {
+            return false;
+        }
+        if (!mSystemRulesVersion.equals(that.mSystemRulesVersion)) {
+            return false;
+        }
+        if (!mDistroFormatVersionSupported.equals(that.mDistroFormatVersionSupported)) {
+            return false;
+        }
+        if (mStagedDistroRulesVersion != null ? !mStagedDistroRulesVersion
+                .equals(that.mStagedDistroRulesVersion) : that.mStagedDistroRulesVersion != null) {
+            return false;
+        }
+        return mInstalledDistroRulesVersion != null ? mInstalledDistroRulesVersion
+                .equals(that.mInstalledDistroRulesVersion)
+                : that.mInstalledDistroRulesVersion == null;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mSystemRulesVersion.hashCode();
+        result = 31 * result + mDistroFormatVersionSupported.hashCode();
+        result = 31 * result + (mOperationInProgress ? 1 : 0);
+        result = 31 * result + mStagedOperationType;
+        result = 31 * result + (mStagedDistroRulesVersion != null ? mStagedDistroRulesVersion
+                .hashCode()
+                : 0);
+        result = 31 * result + mDistroStatus;
+        result = 31 * result + (mInstalledDistroRulesVersion != null ? mInstalledDistroRulesVersion
+                .hashCode() : 0);
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "RulesState{"
+                + "mSystemRulesVersion='" + mSystemRulesVersion + '\''
+                + ", mDistroFormatVersionSupported=" + mDistroFormatVersionSupported
+                + ", mOperationInProgress=" + mOperationInProgress
+                + ", mStagedOperationType=" + mStagedOperationType
+                + ", mStagedDistroRulesVersion=" + mStagedDistroRulesVersion
+                + ", mDistroStatus=" + mDistroStatus
+                + ", mInstalledDistroRulesVersion=" + mInstalledDistroRulesVersion
+                + '}';
+    }
+
+    private static int validateStagedOperation(int stagedOperationType) {
+        if (stagedOperationType < STAGED_OPERATION_UNKNOWN
+                || stagedOperationType > STAGED_OPERATION_INSTALL) {
+            throw new IllegalArgumentException("Unknown operation type=" + stagedOperationType);
+        }
+        return stagedOperationType;
+    }
+
+    private static int validateDistroStatus(int distroStatus) {
+        if (distroStatus < DISTRO_STATUS_UNKNOWN || distroStatus > DISTRO_STATUS_INSTALLED) {
+            throw new IllegalArgumentException("Unknown distro status=" + distroStatus);
+        }
+        return distroStatus;
+    }
+}
diff --git a/core/java/android/app/timezone/RulesUpdaterContract.java b/core/java/android/app/timezone/RulesUpdaterContract.java
new file mode 100644
index 0000000..4e77818
--- /dev/null
+++ b/core/java/android/app/timezone/RulesUpdaterContract.java
@@ -0,0 +1,87 @@
+/*
+ * 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 android.app.timezone;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Constants related to the contract between the Android system and the privileged time zone updater
+ * application.
+ *
+ * @hide
+ */
+// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
+public final class RulesUpdaterContract {
+
+    /**
+     * The system permission possessed by the Android system that allows it to trigger time zone
+     * update checks. The updater should be configured to require this permission when registering
+     * for {@link #ACTION_TRIGGER_RULES_UPDATE_CHECK} intents.
+     */
+    public static final String TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION =
+            android.Manifest.permission.TRIGGER_TIME_ZONE_RULES_CHECK;
+
+    /**
+     * The system permission possessed by the time zone rules updater app that allows it to update
+     * device time zone rules. The Android system requires this permission for calls made to
+     * {@link RulesManager}.
+     */
+    public static final String UPDATE_TIME_ZONE_RULES_PERMISSION =
+            android.Manifest.permission.UPDATE_TIME_ZONE_RULES;
+
+    /**
+     * The action of the intent that the Android system will broadcast. The intent will be targeted
+     * at the configured updater application's package meaning the term "broadcast" only loosely
+     * applies.
+     */
+    public static final String ACTION_TRIGGER_RULES_UPDATE_CHECK =
+            "android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK";
+
+    /**
+     * The extra containing the {@code byte[]} that should be passed to
+     * {@link RulesManager#requestInstall(ParcelFileDescriptor, byte[], Callback)},
+     * {@link RulesManager#requestUninstall(byte[], Callback)} and
+     * {@link RulesManager#requestNothing(byte[], boolean)} methods when the
+     * {@link #ACTION_TRIGGER_RULES_UPDATE_CHECK} intent has been processed.
+     */
+    public static final String EXTRA_CHECK_TOKEN =
+            "android.intent.extra.timezone.CHECK_TOKEN";
+
+    /**
+     * Creates an intent that would trigger a time zone rules update check.
+     */
+    public static Intent createUpdaterIntent(String updaterPackageName) {
+        Intent intent = new Intent(RulesUpdaterContract.ACTION_TRIGGER_RULES_UPDATE_CHECK);
+        intent.setPackage(updaterPackageName);
+        intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
+        return intent;
+    }
+
+    /**
+     * Broadcasts an {@link #ACTION_TRIGGER_RULES_UPDATE_CHECK} intent with the
+     * {@link #EXTRA_CHECK_TOKEN} that triggers an update check, including the required receiver
+     * permission.
+     */
+    public static void sendBroadcast(Context context, String updaterAppPackageName,
+            byte[] checkTokenBytes) {
+        Intent intent = createUpdaterIntent(updaterAppPackageName);
+        intent.putExtra(EXTRA_CHECK_TOKEN, checkTokenBytes);
+        context.sendBroadcast(intent, RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION);
+    }
+}
diff --git a/core/java/android/app/timezone/Utils.java b/core/java/android/app/timezone/Utils.java
new file mode 100644
index 0000000..8dd3fb7
--- /dev/null
+++ b/core/java/android/app/timezone/Utils.java
@@ -0,0 +1,67 @@
+/*
+ * 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 android.app.timezone;
+
+/**
+ * Shared code for android.app.timezone classes.
+ */
+final class Utils {
+    private Utils() {}
+
+    static int validateVersion(String type, int version) {
+        if (version < 0 || version > 999) {
+            throw new IllegalArgumentException("Invalid " + type + " version=" + version);
+        }
+        return version;
+    }
+
+    static String validateRulesVersion(String type, String rulesVersion) {
+        validateNotNull(type, rulesVersion);
+
+        if (rulesVersion.isEmpty()) {
+            throw new IllegalArgumentException(type + " must not be empty");
+        }
+        return rulesVersion;
+    }
+
+    /** Validates that {@code object} is not null. Always returns {@code object}. */
+    static <T> T validateNotNull(String type, T object) {
+        if (object == null) {
+            throw new NullPointerException(type + " == null");
+        }
+        return object;
+    }
+
+    /**
+     * If {@code requireNotNull} is {@code true} calls {@link #validateNotNull(String, Object)},
+     * and {@link #validateNull(String, Object)} otherwise. Returns {@code object}.
+     */
+    static <T> T validateConditionalNull(boolean requireNotNull, String type, T object) {
+        if (requireNotNull) {
+            return validateNotNull(type, object);
+        } else {
+            return validateNull(type, object);
+        }
+    }
+
+    /** Validates that {@code object} is null. Always returns null. */
+    static <T> T validateNull(String type, T object) {
+        if (object != null) {
+            throw new IllegalArgumentException(type + " != null");
+        }
+        return null;
+    }
+}
diff --git a/core/java/android/app/usage/ExternalStorageStats.java b/core/java/android/app/usage/ExternalStorageStats.java
index 83ac779..d7e570f 100644
--- a/core/java/android/app/usage/ExternalStorageStats.java
+++ b/core/java/android/app/usage/ExternalStorageStats.java
@@ -37,30 +37,46 @@
     /**
      * Return the total bytes used by all files in the shared/external storage
      * hosted on this volume.
+     * <p>
+     * This value only includes data which is isolated for each user on a
+     * multiuser device. Any OBB data shared between users is not accounted in
+     * this value.
      */
     public @BytesLong long getTotalBytes() {
         return totalBytes;
     }
 
     /**
-     * Return the total bytes used by audio files in the shared/external storage
-     * hosted on this volume.
+     * Return the total bytes used by all audio files in the shared/external
+     * storage hosted on this volume.
+     * <p>
+     * This value only includes data which is isolated for each user on a
+     * multiuser device. This value does not include any app files which are all
+     * accounted under {@link #getAppBytes()}.
      */
     public @BytesLong long getAudioBytes() {
         return audioBytes;
     }
 
     /**
-     * Return the total bytes used by video files in the shared/external storage
-     * hosted on this volume.
+     * Return the total bytes used by all video files in the shared/external
+     * storage hosted on this volume.
+     * <p>
+     * This value only includes data which is isolated for each user on a
+     * multiuser device. This value does not include any app files which are all
+     * accounted under {@link #getAppBytes()}.
      */
     public @BytesLong long getVideoBytes() {
         return videoBytes;
     }
 
     /**
-     * Return the total bytes used by image files in the shared/external storage
-     * hosted on this volume.
+     * Return the total bytes used by all image files in the shared/external
+     * storage hosted on this volume.
+     * <p>
+     * This value only includes data which is isolated for each user on a
+     * multiuser device. This value does not include any app files which are all
+     * accounted under {@link #getAppBytes()}.
      */
     public @BytesLong long getImageBytes() {
         return imageBytes;
@@ -72,6 +88,9 @@
      * <p>
      * This data is already accounted against individual apps as returned
      * through {@link StorageStats}.
+     * <p>
+     * This value only includes data which is isolated for each user on a
+     * multiuser device.
      */
     public @BytesLong long getAppBytes() {
         return appBytes;
diff --git a/core/java/android/bluetooth/BluetoothA2dp.java b/core/java/android/bluetooth/BluetoothA2dp.java
index d1ad8de..c58eaa1 100644
--- a/core/java/android/bluetooth/BluetoothA2dp.java
+++ b/core/java/android/bluetooth/BluetoothA2dp.java
@@ -136,6 +136,38 @@
      */
     public static final int STATE_NOT_PLAYING   =  11;
 
+    /**
+     * We don't have a stored preference for whether or not the given A2DP sink device supports
+     * optional codecs.
+     * @hide */
+    public static final int OPTIONAL_CODECS_SUPPORT_UNKNOWN = -1;
+
+    /**
+     * The given A2DP sink device does not support optional codecs.
+     * @hide */
+    public static final int OPTIONAL_CODECS_NOT_SUPPORTED = 0;
+
+    /**
+     * The given A2DP sink device does support optional codecs.
+     * @hide */
+    public static final int OPTIONAL_CODECS_SUPPORTED = 1;
+
+    /**
+     * We don't have a stored preference for whether optional codecs should be enabled or disabled
+     * for the given A2DP device.
+     * @hide */
+    public static final int OPTIONAL_CODECS_PREF_UNKNOWN = -1;
+
+    /**
+     * Optional codecs should be disabled for the given A2DP device.
+     * @hide */
+    public static final int OPTIONAL_CODECS_PREF_DISABLED = 0;
+
+    /**
+     *  Optional codecs should be enabled for the given A2DP device.
+     *  @hide */
+    public static final int OPTIONAL_CODECS_PREF_ENABLED = 1;
+
     private Context mContext;
     private ServiceListener mServiceListener;
     private final ReentrantReadWriteLock mServiceLock = new ReentrantReadWriteLock();
@@ -655,6 +687,88 @@
     }
 
     /**
+     * Returns whether this device supports optional codecs.
+     *
+     * @param device The device to check
+     * @return one of OPTIONAL_CODECS_SUPPORT_UNKNOWN, OPTIONAL_CODECS_NOT_SUPPORTED, or
+     *         OPTIONAL_CODECS_SUPPORTED.
+     *
+     * @hide
+     */
+    public int supportsOptionalCodecs(BluetoothDevice device) {
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null && isEnabled() && isValidDevice(device)) {
+                return mService.supportsOptionalCodecs(device);
+            }
+            if (mService == null) Log.w(TAG, "Proxy not attached to service");
+            return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
+            return OPTIONAL_CODECS_SUPPORT_UNKNOWN;
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+    }
+
+    /**
+     * Returns whether this device should have optional codecs enabled.
+     *
+     * @param device The device in question.
+     * @return one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
+     *         OPTIONAL_CODECS_PREF_DISABLED.
+     *
+     * @hide
+     */
+    public int getOptionalCodecsEnabled(BluetoothDevice device) {
+        try {
+            mServiceLock.readLock().lock();
+            if (mService != null && isEnabled() && isValidDevice(device)) {
+                return mService.getOptionalCodecsEnabled(device);
+            }
+            if (mService == null) Log.w(TAG, "Proxy not attached to service");
+            return OPTIONAL_CODECS_PREF_UNKNOWN;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error talking to BT service in getSupportsOptionalCodecs()", e);
+            return OPTIONAL_CODECS_PREF_UNKNOWN;
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+    }
+
+    /**
+     * Sets a persistent preference for whether a given device should have optional codecs enabled.
+     *
+     * @param device The device to set this preference for.
+     * @param value Whether the optional codecs should be enabled for this device.  This should be
+     *              one of OPTIONAL_CODECS_PREF_UNKNOWN, OPTIONAL_CODECS_PREF_ENABLED, or
+     *              OPTIONAL_CODECS_PREF_DISABLED.
+     * @hide
+     */
+    public void setOptionalCodecsEnabled(BluetoothDevice device, int value) {
+        try {
+            if (value != BluetoothA2dp.OPTIONAL_CODECS_PREF_UNKNOWN &&
+                    value != BluetoothA2dp.OPTIONAL_CODECS_PREF_DISABLED &&
+                    value != BluetoothA2dp.OPTIONAL_CODECS_PREF_ENABLED) {
+                Log.e(TAG, "Invalid value passed to setOptionalCodecsEnabled: " + value);
+                return;
+            }
+            mServiceLock.readLock().lock();
+            if (mService != null && isEnabled()
+                    && isValidDevice(device)) {
+                mService.setOptionalCodecsEnabled(device, value);
+            }
+            if (mService == null) Log.w(TAG, "Proxy not attached to service");
+            return;
+        } catch (RemoteException e) {
+            Log.e(TAG, "Stack:" + Log.getStackTraceString(new Throwable()));
+            return;
+        } finally {
+            mServiceLock.readLock().unlock();
+        }
+    }
+
+    /**
      * Helper for converting a state to a string.
      *
      * For debug use only - strings are not internationalized.
diff --git a/core/java/android/bluetooth/IBluetoothA2dp.aidl b/core/java/android/bluetooth/IBluetoothA2dp.aidl
index a775a1f..1b533cb 100644
--- a/core/java/android/bluetooth/IBluetoothA2dp.aidl
+++ b/core/java/android/bluetooth/IBluetoothA2dp.aidl
@@ -42,4 +42,7 @@
     oneway void setCodecConfigPreference(in BluetoothCodecConfig codecConfig);
     oneway void enableOptionalCodecs();
     oneway void disableOptionalCodecs();
+    int supportsOptionalCodecs(in BluetoothDevice device);
+    int getOptionalCodecsEnabled(in BluetoothDevice device);
+    oneway void setOptionalCodecsEnabled(in BluetoothDevice device, int value);
 }
diff --git a/core/java/android/bluetooth/IBluetoothGatt.aidl b/core/java/android/bluetooth/IBluetoothGatt.aidl
index e2d4f5b..dc5c7b6 100644
--- a/core/java/android/bluetooth/IBluetoothGatt.aidl
+++ b/core/java/android/bluetooth/IBluetoothGatt.aidl
@@ -43,10 +43,10 @@
 interface IBluetoothGatt {
     List<BluetoothDevice> getDevicesMatchingConnectionStates(in int[] states);
 
-    void registerScanner(in IScannerCallback callback);
+    void registerScanner(in IScannerCallback callback, in WorkSource workSource);
     void unregisterScanner(in int scannerId);
     void startScan(in int scannerId, in ScanSettings settings, in List<ScanFilter> filters,
-                   in WorkSource workSource, in List scanStorages, in String callingPackage);
+                   in List scanStorages, in String callingPackage);
     void startScanForIntent(in PendingIntent intent, in ScanSettings settings, in List<ScanFilter> filters,
                             in String callingPackage);
     void stopScanForIntent(in PendingIntent intent, in String callingPackage);
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index 5246513..f3f0ae5 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -360,7 +360,7 @@
                 // Scan stopped.
                 if (mScannerId == -1) return;
                 try {
-                    mBluetoothGatt.registerScanner(this);
+                    mBluetoothGatt.registerScanner(this, mWorkSource);
                     wait(REGISTRATION_CALLBACK_TIMEOUT_MILLIS);
                 } catch (InterruptedException | RemoteException e) {
                     Log.e(TAG, "application registeration exception", e);
@@ -424,7 +424,7 @@
                         } else {
                             mScannerId = scannerId;
                             mBluetoothGatt.startScan(mScannerId, mSettings, mFilters,
-                                    mWorkSource, mResultStorages,
+                                    mResultStorages,
                                     ActivityThread.currentOpPackageName());
                         }
                     } catch (RemoteException e) {
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index a8214fa..08c7f18 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -34,7 +34,6 @@
 import android.annotation.UserIdInt;
 import android.app.IApplicationThread;
 import android.app.IServiceConnection;
-import android.app.Notification;
 import android.app.VrManager;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -2660,8 +2659,8 @@
 
     /**
      * Similar to {@link #startService(Intent)}, but with an implicit promise that the
-     * Service will call {@link android.app.Service#startForeground(int, Notification)
-     * startForeground(int, Notification)} once it begins running.  The service is given
+     * Service will call {@link android.app.Service#startForeground(int, android.app.Notification)
+     * startForeground(int, android.app.Notification)} once it begins running.  The service is given
      * an amount of time comparable to the ANR interval to do this, otherwise the system
      * will automatically stop the service and declare the app ANR.
      *
@@ -2682,7 +2681,7 @@
      * or the service can not be found.
      *
      * @see #stopService
-     * @see android.app.Service#startForeground(int, Notification)
+     * @see android.app.Service#startForeground(int, android.app.Notification)
      */
     @Nullable
     public abstract ComponentName startForegroundService(Intent service);
@@ -2865,6 +2864,7 @@
             STORAGE_SERVICE,
             STORAGE_STATS_SERVICE,
             WALLPAPER_SERVICE,
+            TIME_ZONE_RULES_MANAGER_SERVICE,
             VIBRATOR_SERVICE,
             //@hide: STATUS_BAR_SERVICE,
             CONNECTIVITY_SERVICE,
@@ -3968,6 +3968,15 @@
     public static final String VR_SERVICE = "vrmanager";
 
     /**
+     * Use with {@link #getSystemService} to retrieve an
+     * {@link android.app.timezone.ITimeZoneRulesManager}.
+     * @hide
+     *
+     * @see #getSystemService
+     */
+    public static final String TIME_ZONE_RULES_MANAGER_SERVICE = "timezone";
+
+    /**
      * Determine whether the given permission is allowed for a particular
      * process and user ID running in the system.
      *
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 5264cd7..e127ca3 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -952,4 +952,12 @@
     public Handler getMainThreadHandler() {
         return mBase.getMainThreadHandler();
     }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int getNextAccessibilityId() {
+        return mBase.getNextAccessibilityId();
+    }
 }
diff --git a/core/java/android/content/pm/AuxiliaryResolveInfo.java b/core/java/android/content/pm/AuxiliaryResolveInfo.java
index 69bfeca..323733c 100644
--- a/core/java/android/content/pm/AuxiliaryResolveInfo.java
+++ b/core/java/android/content/pm/AuxiliaryResolveInfo.java
@@ -43,13 +43,16 @@
     public final String token;
     /** The version code of the package */
     public final int versionCode;
+    /** An intent to start upon failure to install */
+    public final Intent failureIntent;
 
     /** Create a response for installing an instant application. */
     public AuxiliaryResolveInfo(@NonNull InstantAppResolveInfo resolveInfo,
             @NonNull IntentFilter orig,
             @Nullable String splitName,
             @NonNull String token,
-            boolean needsPhase2) {
+            boolean needsPhase2,
+            @Nullable Intent failureIntent) {
         super(orig);
         this.resolveInfo = resolveInfo;
         this.packageName = resolveInfo.getPackageName();
@@ -57,12 +60,14 @@
         this.token = token;
         this.needsPhaseTwo = needsPhase2;
         this.versionCode = resolveInfo.getVersionCode();
+        this.failureIntent = failureIntent;
     }
 
     /** Create a response for installing a split on demand. */
     public AuxiliaryResolveInfo(@NonNull String packageName,
             @Nullable String splitName,
-            int versionCode) {
+            int versionCode,
+            @Nullable Intent failureIntent) {
         super();
         this.packageName = packageName;
         this.splitName = splitName;
@@ -70,5 +75,6 @@
         this.resolveInfo = null;
         this.token = null;
         this.needsPhaseTwo = false;
+        this.failureIntent = failureIntent;
     }
 }
\ No newline at end of file
diff --git a/core/java/android/content/pm/InstantAppResolveInfo.java b/core/java/android/content/pm/InstantAppResolveInfo.java
index 603192a..dcaf66e 100644
--- a/core/java/android/content/pm/InstantAppResolveInfo.java
+++ b/core/java/android/content/pm/InstantAppResolveInfo.java
@@ -47,7 +47,7 @@
     private final int mVersionCode;
 
     public InstantAppResolveInfo(@NonNull InstantAppDigest digest, @Nullable String packageName,
-            @Nullable List<InstantAppIntentFilter> filters, int versionConde) {
+            @Nullable List<InstantAppIntentFilter> filters, int versionCode) {
         // validate arguments
         if ((packageName == null && (filters != null && filters.size() != 0))
                 || (packageName != null && (filters == null || filters.size() == 0))) {
@@ -61,7 +61,7 @@
             mFilters = null;
         }
         mPackageName = packageName;
-        mVersionCode = versionConde;
+        mVersionCode = versionCode;
     }
 
     public InstantAppResolveInfo(@NonNull String hostName, @Nullable String packageName,
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index ee56a18..4e53914 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -44,7 +44,6 @@
     public boolean notLaunched;
     public boolean hidden; // Is the app restricted by owner / admin
     public boolean suspended;
-    public boolean blockUninstall;
     public boolean instantApp;
     public int enabled;
     public String lastDisableAppCaller;
@@ -75,7 +74,6 @@
         notLaunched = o.notLaunched;
         hidden = o.hidden;
         suspended = o.suspended;
-        blockUninstall = o.blockUninstall;
         instantApp = o.instantApp;
         enabled = o.enabled;
         lastDisableAppCaller = o.lastDisableAppCaller;
@@ -193,9 +191,6 @@
         if (suspended != oldState.suspended) {
             return false;
         }
-        if (blockUninstall != oldState.blockUninstall) {
-            return false;
-        }
         if (instantApp != oldState.instantApp) {
             return false;
         }
diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java
index 2b76ae2..d0c6397 100644
--- a/core/java/android/content/pm/ShortcutInfo.java
+++ b/core/java/android/content/pm/ShortcutInfo.java
@@ -23,7 +23,6 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.res.Resources;
 import android.content.res.Resources.NotFoundException;
@@ -96,6 +95,9 @@
     public static final int FLAG_ADAPTIVE_BITMAP = 1 << 9;
 
     /** @hide */
+    public static final int FLAG_RETURNED_BY_SERVICE = 1 << 10;
+
+    /** @hide */
     @IntDef(flag = true,
             value = {
             FLAG_DYNAMIC,
@@ -108,6 +110,7 @@
             FLAG_STRINGS_RESOLVED,
             FLAG_IMMUTABLE,
             FLAG_ADAPTIVE_BITMAP,
+            FLAG_RETURNED_BY_SERVICE
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ShortcutFlags {}
@@ -1343,6 +1346,16 @@
         return (mFlags & flags) == flags;
     }
 
+    /** @hide */
+    public boolean isReturnedByServer() {
+        return hasFlags(FLAG_RETURNED_BY_SERVICE);
+    }
+
+    /** @hide */
+    public void setReturnedByServer() {
+        addFlags(FLAG_RETURNED_BY_SERVICE);
+    }
+
     /** Return whether a shortcut is dynamic. */
     public boolean isDynamic() {
         return hasFlags(FLAG_DYNAMIC);
@@ -1450,7 +1463,7 @@
 
     /**
      * Return whether a shortcut's icon is adaptive bitmap following design guideline
-     * defined in {@link AdaptiveIconDrawable}.
+     * defined in {@link android.graphics.drawable.AdaptiveIconDrawable}.
      *
      * @hide internal/unit tests only
      */
@@ -1776,6 +1789,9 @@
         if (hasStringResourcesResolved()) {
             sb.append("Sr");
         }
+        if (isReturnedByServer()) {
+            sb.append("V");
+        }
         sb.append("]");
 
         sb.append(", packageName=");
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index a7c09b5..e3e0cc5 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -618,6 +618,10 @@
     /**
      * Return all dynamic shortcuts from the caller app.
      *
+     * <p>This API is intended to be used for examining what shortcuts are currently published.
+     * Re-publishing returned {@link ShortcutInfo}s via APIs such as
+     * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons.
+     *
      * @throws IllegalStateException when the user is locked.
      */
     @NonNull
@@ -633,6 +637,10 @@
     /**
      * Return all static (manifest) shortcuts from the caller app.
      *
+     * <p>This API is intended to be used for examining what shortcuts are currently published.
+     * Re-publishing returned {@link ShortcutInfo}s via APIs such as
+     * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons.
+     *
      * @throws IllegalStateException when the user is locked.
      */
     @NonNull
@@ -697,6 +705,10 @@
     /**
      * Return all pinned shortcuts from the caller app.
      *
+     * <p>This API is intended to be used for examining what shortcuts are currently published.
+     * Re-publishing returned {@link ShortcutInfo}s via APIs such as
+     * {@link #setDynamicShortcuts(List)} may cause loss of information such as icons.
+     *
      * @throws IllegalStateException when the user is locked.
      */
     @NonNull
diff --git a/core/java/android/content/res/FontResourcesParser.java b/core/java/android/content/res/FontResourcesParser.java
index b21ccf1..042eb87 100644
--- a/core/java/android/content/res/FontResourcesParser.java
+++ b/core/java/android/content/res/FontResourcesParser.java
@@ -18,6 +18,7 @@
 import com.android.internal.R;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.graphics.Typeface;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
@@ -36,8 +37,6 @@
  */
 public class FontResourcesParser {
     private static final String TAG = "FontResourcesParser";
-    private static final int NORMAL_WEIGHT = 400;
-    private static final int ITALIC = 1;
 
     // A class represents single entry of font-family in xml file.
     public interface FamilyResourceEntry {}
@@ -78,10 +77,10 @@
     public static final class FontFileResourceEntry {
         private final @NonNull String mFileName;
         private int mWeight;
-        private boolean mItalic;
+        private int mItalic;
         private int mResourceId;
 
-        public FontFileResourceEntry(@NonNull String fileName, int weight, boolean italic) {
+        public FontFileResourceEntry(@NonNull String fileName, int weight, int italic) {
             mFileName = fileName;
             mWeight = weight;
             mItalic = italic;
@@ -95,7 +94,7 @@
             return mWeight;
         }
 
-        public boolean isItalic() {
+        public int getItalic() {
             return mItalic;
         }
     }
@@ -200,8 +199,10 @@
             throws XmlPullParserException, IOException {
         AttributeSet attrs = Xml.asAttributeSet(parser);
         TypedArray array = resources.obtainAttributes(attrs, R.styleable.FontFamilyFont);
-        int weight = array.getInt(R.styleable.FontFamilyFont_fontWeight, NORMAL_WEIGHT);
-        boolean isItalic = ITALIC == array.getInt(R.styleable.FontFamilyFont_fontStyle, 0);
+        int weight = array.getInt(R.styleable.FontFamilyFont_fontWeight,
+                Typeface.RESOLVE_BY_FONT_TABLE);
+        int italic = array.getInt(R.styleable.FontFamilyFont_fontStyle,
+                Typeface.RESOLVE_BY_FONT_TABLE);
         String filename = array.getString(R.styleable.FontFamilyFont_font);
         array.recycle();
         while (parser.next() != XmlPullParser.END_TAG) {
@@ -210,7 +211,7 @@
         if (filename == null) {
             return null;
         }
-        return new FontFileResourceEntry(filename, weight, isItalic);
+        return new FontFileResourceEntry(filename, weight, italic);
     }
 
     private static void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 211d54d..63eedf5 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -107,7 +107,8 @@
     /**
      * Create a request suitable for zero shutter lag still capture. This means
      * means maximizing image quality without compromising preview frame rate.
-     * AE/AWB/AF should be on auto mode.
+     * AE/AWB/AF should be on auto mode. This is intended for application-operated ZSL. For
+     * device-operated ZSL, use {@link CaptureRequest#CONTROL_ENABLE_ZSL} if available.
      * This template is guaranteed to be supported on camera devices that support the
      * {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING PRIVATE_REPROCESSING}
      * capability or the
@@ -115,6 +116,7 @@
      * capability.
      *
      * @see #createCaptureRequest
+     * @see CaptureRequest#CONTROL_ENABLE_ZSL
      */
     public static final int TEMPLATE_ZERO_SHUTTER_LAG = 5;
 
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 279d73d..c41fc02 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1669,6 +1669,7 @@
      * <code>false</code> if present.</p>
      * <p>For applications targeting SDK versions older than O, the value of enableZsl in all
      * capture templates is always <code>false</code> if present.</p>
+     * <p>For application-operated ZSL, use CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG template.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index aedfc4b..6d80c20 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2174,6 +2174,7 @@
      * <code>false</code> if present.</p>
      * <p>For applications targeting SDK versions older than O, the value of enableZsl in all
      * capture templates is always <code>false</code> if present.</p>
+     * <p>For application-operated ZSL, use CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG template.</p>
      * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
      *
      * @see CaptureRequest#CONTROL_CAPTURE_INTENT
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 7947620..d61fb97 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -42,8 +42,8 @@
 import javax.crypto.Mac;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
-import static android.Manifest.permission.USE_FINGERPRINT;
 import static android.Manifest.permission.MANAGE_FINGERPRINT;
+import static android.Manifest.permission.USE_FINGERPRINT;
 
 /**
  * A class that coordinates access to the fingerprint hardware.
@@ -910,6 +910,7 @@
             } else if (mAuthenticationCallback != null) {
                 mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
                         getErrorString(errMsgId, vendorCode));
+                mAuthenticationCallback = null;
             } else if (mRemovalCallback != null) {
                 mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId,
                         getErrorString(errMsgId, vendorCode));
@@ -930,12 +931,14 @@
                 final AuthenticationResult result =
                         new AuthenticationResult(mCryptoObject, fp, userId);
                 mAuthenticationCallback.onAuthenticationSucceeded(result);
+                mAuthenticationCallback = null;
             }
         }
 
         private void sendAuthenticatedFailed() {
             if (mAuthenticationCallback != null) {
-               mAuthenticationCallback.onAuthenticationFailed();
+                mAuthenticationCallback.onAuthenticationFailed();
+                mAuthenticationCallback = null;
             }
         }
 
diff --git a/core/java/android/hardware/input/IInputManager.aidl b/core/java/android/hardware/input/IInputManager.aidl
index bdb278b..4586316 100644
--- a/core/java/android/hardware/input/IInputManager.aidl
+++ b/core/java/android/hardware/input/IInputManager.aidl
@@ -34,6 +34,11 @@
     InputDevice getInputDevice(int deviceId);
     int[] getInputDeviceIds();
 
+    // Enable/disable input device.
+    boolean isInputDeviceEnabled(int deviceId);
+    void enableInputDevice(int deviceId);
+    void disableInputDevice(int deviceId);
+
     // Reports whether the hardware supports the given keys; returns true if successful
     boolean hasKeys(int deviceId, int sourceMask, in int[] keyCodes, out boolean[] keyExists);
 
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index 631b77d..22b3638 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -16,8 +16,6 @@
 
 package android.hardware.input;
 
-import com.android.internal.os.SomeArgs;
-
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
@@ -31,10 +29,10 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
-import android.os.Vibrator;
-import android.os.VibrationEffect;
 import android.os.ServiceManager.ServiceNotFoundException;
+import android.os.SystemClock;
+import android.os.VibrationEffect;
+import android.os.Vibrator;
 import android.provider.Settings;
 import android.provider.Settings.SettingNotFoundException;
 import android.util.Log;
@@ -46,6 +44,8 @@
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
 
+import com.android.internal.os.SomeArgs;
+
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -323,6 +323,62 @@
     }
 
     /**
+     * Returns true if an input device is enabled. Should return true for most
+     * situations. Some system apps may disable an input device, for
+     * example to prevent unwanted touch events.
+     *
+     * @param id The input device Id.
+     *
+     * @hide
+     */
+    public boolean isInputDeviceEnabled(int id) {
+        try {
+            return mIm.isInputDeviceEnabled(id);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Could not check enabled status of input device with id = " + id);
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Enables an InputDevice.
+     * <p>
+     * Requires {@link android.Manifest.permissions.DISABLE_INPUT_DEVICE}.
+     * </p>
+     *
+     * @param id The input device Id.
+     *
+     * @hide
+     */
+    public void enableInputDevice(int id) {
+        try {
+            mIm.enableInputDevice(id);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Could not enable input device with id = " + id);
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Disables an InputDevice.
+     * <p>
+     * Requires {@link android.Manifest.permissions.DISABLE_INPUT_DEVICE}.
+     * </p>
+     *
+     * @param id The input device Id.
+     *
+     * @hide
+     */
+    public void disableInputDevice(int id) {
+        try {
+            mIm.disableInputDevice(id);
+        } catch (RemoteException ex) {
+            Log.w(TAG, "Could not disable input device with id = " + id);
+            throw ex.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Registers an input device listener to receive notifications about when
      * input devices are added, removed or changed.
      *
diff --git a/core/java/android/hardware/radio/ITuner.aidl b/core/java/android/hardware/radio/ITuner.aidl
index c08f41f..0eded8f 100644
--- a/core/java/android/hardware/radio/ITuner.aidl
+++ b/core/java/android/hardware/radio/ITuner.aidl
@@ -30,4 +30,32 @@
     RadioManager.BandConfig getConfiguration();
 
     int getProgramInformation(out RadioManager.ProgramInfo[] infoOut);
+
+    /**
+     * @throws IllegalStateException if tuner was opened without audio
+     */
+    void setMuted(boolean mute);
+
+    boolean isMuted();
+
+    /**
+     * @throws IllegalStateException if called out of sequence
+     */
+    void step(boolean directionDown, boolean skipSubChannel);
+
+    /**
+     * @throws IllegalStateException if called out of sequence
+     */
+    void scan(boolean directionDown, boolean skipSubChannel);
+
+    /**
+     * @throws IllegalArgumentException if invalid arguments are passed
+     * @throws IllegalStateException if called out of sequence
+     */
+    void tune(int channel, int subChannel);
+
+    /**
+     * @throws IllegalStateException if called out of sequence
+     */
+    void cancel();
 }
diff --git a/core/java/android/hardware/radio/ITunerCallback.aidl b/core/java/android/hardware/radio/ITunerCallback.aidl
index 8ea7491..b32c683 100644
--- a/core/java/android/hardware/radio/ITunerCallback.aidl
+++ b/core/java/android/hardware/radio/ITunerCallback.aidl
@@ -22,4 +22,5 @@
 oneway interface ITunerCallback {
     void onError(int status);
     void onConfigurationChanged(in RadioManager.BandConfig config);
+    void onProgramInfoChanged(in RadioManager.ProgramInfo info);
 }
diff --git a/core/java/android/hardware/radio/TunerAdapter.java b/core/java/android/hardware/radio/TunerAdapter.java
index 1156fe8..3a097a5 100644
--- a/core/java/android/hardware/radio/TunerAdapter.java
+++ b/core/java/android/hardware/radio/TunerAdapter.java
@@ -21,7 +21,6 @@
 import android.os.RemoteException;
 import android.util.Log;
 
-import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -65,7 +64,8 @@
             Log.e(TAG, "Can't set configuration", e);
             return RadioManager.STATUS_BAD_VALUE;
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "service died", e);
+            return RadioManager.STATUS_DEAD_OBJECT;
         }
     }
 
@@ -78,32 +78,61 @@
             config[0] = mTuner.getConfiguration();
             return RadioManager.STATUS_OK;
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "service died", e);
+            return RadioManager.STATUS_DEAD_OBJECT;
         }
     }
 
     @Override
     public int setMute(boolean mute) {
-        // TODO(b/36863239): forward to mTuner
-        throw new RuntimeException("Not implemented");
+        try {
+            mTuner.setMuted(mute);
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "Can't set muted", e);
+            return RadioManager.STATUS_ERROR;
+        } catch (RemoteException e) {
+            Log.e(TAG, "service died", e);
+            return RadioManager.STATUS_DEAD_OBJECT;
+        }
+        return RadioManager.STATUS_OK;
     }
 
     @Override
     public boolean getMute() {
-        // TODO(b/36863239): forward to mTuner
-        throw new RuntimeException("Not implemented");
+        try {
+            return mTuner.isMuted();
+        } catch (RemoteException e) {
+            Log.e(TAG, "service died", e);
+            return true;
+        }
     }
 
     @Override
     public int step(int direction, boolean skipSubChannel) {
-        // TODO(b/36863239): forward to mTuner
-        throw new RuntimeException("Not implemented");
+        try {
+            mTuner.step(direction == RadioTuner.DIRECTION_DOWN, skipSubChannel);
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "Can't step", e);
+            return RadioManager.STATUS_INVALID_OPERATION;
+        } catch (RemoteException e) {
+            Log.e(TAG, "service died", e);
+            return RadioManager.STATUS_DEAD_OBJECT;
+        }
+        return RadioManager.STATUS_OK;
     }
 
     @Override
     public int scan(int direction, boolean skipSubChannel) {
-        // TODO(b/36863239): forward to mTuner
-        throw new RuntimeException("Not implemented");
+        try {
+            mTuner.scan(direction == RadioTuner.DIRECTION_DOWN, skipSubChannel);
+        } catch (IllegalStateException e) {
+            Log.e(TAG, "Can't scan", e);
+            return RadioManager.STATUS_INVALID_OPERATION;
+        } catch (RemoteException e) {
+            Log.e(TAG, "service died", e);
+            return RadioManager.STATUS_DEAD_OBJECT;
+        }
+        return RadioManager.STATUS_OK;
     }
 
     @Override
@@ -126,7 +155,8 @@
         try {
             return mTuner.getProgramInformation(info);
         } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
+            Log.e(TAG, "service died", e);
+            return RadioManager.STATUS_DEAD_OBJECT;
         }
     }
 
diff --git a/core/java/android/hardware/radio/TunerCallbackAdapter.java b/core/java/android/hardware/radio/TunerCallbackAdapter.java
index 8268e4d..ba85017 100644
--- a/core/java/android/hardware/radio/TunerCallbackAdapter.java
+++ b/core/java/android/hardware/radio/TunerCallbackAdapter.java
@@ -20,18 +20,11 @@
 import android.annotation.Nullable;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.util.ArrayList;
-import java.util.List;
 
 /**
  * Implements the ITunerCallback interface by forwarding calls to RadioTuner.Callback.
  */
 class TunerCallbackAdapter extends ITunerCallback.Stub {
-    private static final String TAG = "radio.TunerCallbackAdapter";
-
     @NonNull private final RadioTuner.Callback mCallback;
     @NonNull private final Handler mHandler;
 
@@ -53,4 +46,9 @@
     public void onConfigurationChanged(RadioManager.BandConfig config) {
         mHandler.post(() -> mCallback.onConfigurationChanged(config));
     }
+
+    @Override
+    public void onProgramInfoChanged(RadioManager.ProgramInfo info) {
+        mHandler.post(() -> mCallback.onProgramInfoChanged(info));
+    }
 }
diff --git a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
index ad20ce5..160376b 100644
--- a/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
+++ b/core/java/android/hardware/soundtrigger/KeyphraseEnrollmentInfo.java
@@ -341,7 +341,8 @@
               }
           }
         }
-        Slog.w(TAG, "No Enrollment application supports the given keyphrase/locale");
+        Slog.w(TAG, "No enrollment application supports the given keyphrase/locale: '"
+                + keyphrase + "'/" + locale);
         return null;
     }
 
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 73e52c8..d163a44 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -45,7 +45,7 @@
      * Set the active scorer and clear existing scores.
      * @param packageName the package name of the new scorer to use.
      * @return true if the operation succeeded, or false if the new package is not a valid scorer.
-     * @throws SecurityException if the caller is not the system.
+     * @throws SecurityException if the caller is not the system or a network scorer.
      */
     boolean setActiveScorer(in String packageName);
 
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index eeb426a..9f6e45c 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -16,27 +16,20 @@
 
 package android.net;
 
-import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
-
+import android.Manifest.permission;
 import android.annotation.IntDef;
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.ServiceManager.ServiceNotFoundException;
-import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
-import java.util.concurrent.CompletableFuture;
 
 /**
  * Class that manages communication between network subsystems and a network scorer.
@@ -49,9 +42,9 @@
  *
  * <p>A network scorer is any application which:
  * <ul>
- * <li>Declares the {@link android.Manifest.permission#SCORE_NETWORKS} permission.
+ * <li>Declares the {@link permission#SCORE_NETWORKS} permission.
  * <li>Include a Service for the {@link #ACTION_RECOMMEND_NETWORKS} action
- *     protected by the {@link android.Manifest.permission#BIND_NETWORK_RECOMMENDATION_SERVICE}
+ *     protected by the {@link permission#BIND_NETWORK_RECOMMENDATION_SERVICE}
  *     permission.
  * </ul>
  *
@@ -319,7 +312,7 @@
      *
      * @return true if the operation succeeded, or false if the new package is not a valid scorer.
      * @throws SecurityException if the caller is not a system process or does not hold the
-     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission
+     *         {@link permission#SCORE_NETWORKS} permission
      * @hide
      */
     @SystemApi
@@ -351,7 +344,7 @@
      *
      * @return true if the broadcast was sent, or false if there is no active scorer.
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
+     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
      * @hide
      */
     public boolean requestScores(NetworkKey[] networks) throws SecurityException {
@@ -368,7 +361,7 @@
      * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
+     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
      * @throws IllegalArgumentException if a score cache is already registered for this type.
      * @deprecated equivalent to registering for cache updates with CACHE_FILTER_NONE.
      * @hide
@@ -385,7 +378,7 @@
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores
      * @param filterType the {@link CacheUpdateFilter} to apply
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
+     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
      * @throws IllegalArgumentException if a score cache is already registered for this type.
      * @hide
      */
@@ -404,7 +397,7 @@
      * @param networkType the type of network this cache can handle. See {@link NetworkKey#type}.
      * @param scoreCache implementation of {@link INetworkScoreCache} to store the scores.
      * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
+     *         {@link permission#REQUEST_NETWORK_SCORES} permission.
      * @throws IllegalArgumentException if a score cache is already registered for this type.
      * @hide
      */
@@ -417,25 +410,6 @@
     }
 
     /**
-     * Request a recommendation for which network to connect to.
-     *
-     * <p>It is not safe to call this method from the main thread.
-     *
-     * @param request a {@link RecommendationRequest} instance containing additional
-     *                request details
-     * @return a {@link RecommendationResult} instance containing the recommended network
-     *         to connect to
-     * @throws SecurityException if the caller does not hold the
-     *         {@link android.Manifest.permission#REQUEST_NETWORK_SCORES} permission.
-     * @hide
-     * @deprecated to be removed.
-     */
-    public RecommendationResult requestRecommendation(RecommendationRequest request)
-            throws SecurityException {
-        return null;
-    }
-
-    /**
      * Determine whether the application with the given UID is the enabled scorer.
      *
      * @param callingUid the UID to check
diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java
index b56437e..0b1569c 100644
--- a/core/java/android/net/SSLCertificateSocketFactory.java
+++ b/core/java/android/net/SSLCertificateSocketFactory.java
@@ -20,6 +20,7 @@
 import android.util.Log;
 
 import com.android.internal.os.RoSystemProperties;
+import com.android.org.conscrypt.Conscrypt;
 import com.android.org.conscrypt.OpenSSLContextImpl;
 import com.android.org.conscrypt.OpenSSLSocketImpl;
 import com.android.org.conscrypt.SSLClientSessionCache;
@@ -212,7 +213,7 @@
     private SSLSocketFactory makeSocketFactory(
             KeyManager[] keyManagers, TrustManager[] trustManagers) {
         try {
-            OpenSSLContextImpl sslContext = OpenSSLContextImpl.getPreferred();
+            OpenSSLContextImpl sslContext =  (OpenSSLContextImpl) Conscrypt.newPreferredSSLContextSpi();
             sslContext.engineInit(keyManagers, trustManagers, null);
             sslContext.engineGetClientSessionContext().setPersistentCache(mSessionCache);
             return sslContext.engineGetSocketFactory();
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 235f24c..37c153f 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -183,8 +183,10 @@
      *   - Wakelock data (wl) gets current and max times.
      * New in version 20:
      *   - Background timers and counters for: Sensor, BluetoothScan, WifiScan, Jobs, Syncs.
+     * New in version 21:
+     *   - Actual (not just apportioned) Wakelock time is also recorded.
      */
-    static final String CHECKIN_VERSION = "20";
+    static final String CHECKIN_VERSION = "21";
 
     /**
      * Old version, we hit 9 and ran out of room, need to remove.
@@ -194,7 +196,7 @@
     private static final long BYTES_PER_KB = 1024;
     private static final long BYTES_PER_MB = 1048576; // 1024^2
     private static final long BYTES_PER_GB = 1073741824; //1024^3
-    
+
     private static final String VERSION_DATA = "vers";
     private static final String UID_DATA = "uid";
     private static final String WAKEUP_ALARM_DATA = "wua";
@@ -205,6 +207,12 @@
     private static final String VIBRATOR_DATA = "vib";
     private static final String FOREGROUND_DATA = "fg";
     private static final String STATE_TIME_DATA = "st";
+    // wl line is:
+    // BATTERY_STATS_CHECKIN_VERSION, uid, which, "wl", name,
+    // full totalTime,    'f', count, current duration, max duration, total duration,
+    // partial totalTime, 'p', count, current duration, max duration, total duration,
+    // window totalTime,  'w', count, current duration, max duration, total duration
+    // [Currently, full and window wakelocks have durations current = max = total = -1]
     private static final String WAKELOCK_DATA = "wl";
     private static final String SYNC_DATA = "sy";
     private static final String JOB_DATA = "jb";
@@ -2659,6 +2667,12 @@
                     sb.append(" max=");
                     sb.append(maxDurationMs);
                 }
+                // Put actual time if it is available and different from totalTimeMillis.
+                final long totalDurMs = timer.getTotalDurationMsLocked(elapsedRealtimeUs/1000);
+                if (totalDurMs > totalTimeMillis) {
+                    sb.append(" actual=");
+                    sb.append(totalDurMs);
+                }
                 if (timer.isRunningLocked()) {
                     final long currentMs = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
                     if (currentMs >= 0) {
@@ -2742,13 +2756,15 @@
             long elapsedRealtimeUs, String name, int which, String linePrefix) {
         long totalTimeMicros = 0;
         int count = 0;
-        long max = -1;
-        long current = -1;
+        long max = 0;
+        long current = 0;
+        long totalDuration = 0;
         if (timer != null) {
             totalTimeMicros = timer.getTotalTimeLocked(elapsedRealtimeUs, which);
-            count = timer.getCountLocked(which); 
+            count = timer.getCountLocked(which);
             current = timer.getCurrentDurationMsLocked(elapsedRealtimeUs/1000);
             max = timer.getMaxDurationMsLocked(elapsedRealtimeUs/1000);
+            totalDuration = timer.getTotalDurationMsLocked(elapsedRealtimeUs/1000);
         }
         sb.append(linePrefix);
         sb.append((totalTimeMicros + 500) / 1000); // microseconds to milliseconds with rounding
@@ -2759,9 +2775,16 @@
         sb.append(current);
         sb.append(',');
         sb.append(max);
+        // Partial, full, and window wakelocks are pooled, so totalDuration is meaningful (albeit
+        // not always tracked). Kernel wakelocks (which have name == null) have no notion of
+        // totalDuration independent of totalTimeMicros (since they are not pooled).
+        if (name != null) {
+            sb.append(',');
+            sb.append(totalDuration);
+        }
         return ",";
     }
-    
+
     private static final void dumpLineHeader(PrintWriter pw, int uid, String category,
                                              String type) {
         pw.print(BATTERY_STATS_CHECKIN_VERSION);
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 4bad7ab..86fcfc8 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -758,7 +758,7 @@
         /**
          * O.
          */
-        public static final int O = 26;
+        public static final int O = CUR_DEVELOPMENT; // STOPSHIP Replace with the real version.
     }
 
     /** The type of build, like "user" or "eng". */
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index eceaa31..6aa601a 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -189,10 +189,11 @@
             if (mAmplitude < -1 || mAmplitude == 0 || mAmplitude > 255) {
                 throw new IllegalArgumentException(
                         "amplitude must either be DEFAULT_AMPLITUDE, " +
-                        "or between 1 and 255 inclusive");
+                        "or between 1 and 255 inclusive (amplitude=" + mAmplitude + ")");
             }
             if (mTiming <= 0) {
-                throw new IllegalArgumentException("timing must be positive");
+                throw new IllegalArgumentException(
+                        "timing must be positive (timing=" + mTiming + ")");
             }
         }
 
@@ -274,24 +275,31 @@
         public void validate() {
             if (mTimings.length != mAmplitudes.length) {
                 throw new IllegalArgumentException(
-                        "timing and amplitude arrays must be of equal length");
+                        "timing and amplitude arrays must be of equal length" +
+                        " (timings.length=" + mTimings.length +
+                        ", amplitudes.length=" + mAmplitudes.length + ")");
             }
             if (!hasNonZeroEntry(mTimings)) {
-                throw new IllegalArgumentException("at least one timing must be non-zero");
+                throw new IllegalArgumentException("at least one timing must be non-zero" +
+                        " (timings=" + Arrays.toString(mTimings) + ")");
             }
             for (long timing : mTimings) {
                 if (timing < 0) {
-                    throw new IllegalArgumentException("timings must all be >= 0");
+                    throw new IllegalArgumentException("timings must all be >= 0" +
+                            " (timings=" + Arrays.toString(mTimings) + ")");
                 }
             }
             for (int amplitude : mAmplitudes) {
                 if (amplitude < -1 || amplitude > 255) {
                     throw new IllegalArgumentException(
-                            "amplitudes must all be DEFAULT_AMPLITUDE or between 0 and 255");
+                            "amplitudes must all be DEFAULT_AMPLITUDE or between 0 and 255" +
+                            " (amplitudes=" + Arrays.toString(mAmplitudes) + ")");
                 }
             }
             if (mRepeat < -1 || mRepeat >= mTimings.length) {
-                throw new IllegalArgumentException("repeat index must be >= -1");
+                throw new IllegalArgumentException(
+                        "repeat index must be within the bounds of the timings array" +
+                        " (timings.length=" + mTimings.length + ", index=" + mRepeat +")");
             }
         }
 
@@ -375,7 +383,8 @@
         @Override
         public void validate() {
             if (mEffectId != EFFECT_CLICK) {
-                throw new IllegalArgumentException("Unknown prebaked effect type");
+                throw new IllegalArgumentException(
+                        "Unknown prebaked effect type (value=" + mEffectId + ")");
             }
         }
 
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index 1e55c78..2f0eeca 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -157,6 +157,8 @@
         // This call needs to continue throwing ArrayIndexOutOfBoundsException but ignore all other
         // exceptions for compatibility purposes
         if (repeat < -1 || repeat >= pattern.length) {
+            Log.e(TAG, "vibrate called with repeat index out of bounds" +
+                    " (pattern.length=" + pattern.length + ", index=" + repeat + ")");
             throw new ArrayIndexOutOfBoundsException();
         }
 
diff --git a/core/java/android/os/VintfObject.java b/core/java/android/os/VintfObject.java
index 1ef3916..65b33e5 100644
--- a/core/java/android/os/VintfObject.java
+++ b/core/java/android/os/VintfObject.java
@@ -16,27 +16,25 @@
 
 package android.os;
 
-import java.util.ArrayList;
+import java.util.Map;
 
 import android.util.Log;
 
-/** @hide */
+/**
+ * Java API for libvintf.
+ * @hide
+ */
 public class VintfObject {
 
-    private static final String LOG_TAG = "VintfObject";
+    /// ---------- OTA
 
     /**
-     * Slurps all device information (both manifests)
-     * and report it.
+     * Slurps all device information (both manifests and both matrices)
+     * and report them.
      * If any error in getting one of the manifests, it is not included in
      * the list.
      */
-    public static String[] report() {
-        ArrayList<String> ret = new ArrayList<>();
-        put(ret, getDeviceManifest(), "device manifest");
-        put(ret, getFrameworkManifest(), "framework manifest");
-        return ret.toArray(new String[0]);
-    }
+    public static native String[] report();
 
     /**
      * Verify that the given metadata for an OTA package is compatible with
@@ -50,15 +48,26 @@
      */
     public static native int verify(String[] packageInfo);
 
-    // return null if any error, otherwise XML string.
-    private static native String getDeviceManifest();
-    private static native String getFrameworkManifest();
+    /// ---------- CTS Device Info
 
-    private static void put(ArrayList<String> list, String content, String message) {
-        if (content == null || content.length() == 0) {
-            Log.e(LOG_TAG, "Cannot get;" + message + "; check native logs for details.");
-            return;
-        }
-        list.add(content);
-    }
+    /**
+     * @return a list of HAL names and versions that is supported by this
+     * device as stated in device and framework manifests. For example,
+     * ["android.hidl.manager@1.0", "android.hardware.camera.device@1.0",
+     *  "android.hardware.camera.device@3.2"]. There are no duplicates.
+     */
+    public static native String[] getHalNamesAndVersions();
+
+    /**
+     * @return the BOARD_SEPOLICY_VERS build flag available in device manifest.
+     */
+    public static native String getSepolicyVersion();
+
+    /**
+     * @return a list of VNDK snapshots supported by the framework, as
+     * specified in framework manifest. For example,
+     * [("25.0.5", ["libjpeg.so", "libbase.so"]),
+     *  ("25.1.3", ["libjpeg.so", "libbase.so"])]
+     */
+    public static native Map<String, String[]> getVndkSnapshots();
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1063a46..4a6d8ce 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5176,13 +5176,6 @@
         public static final String AUTOFILL_SERVICE = "autofill_service";
 
         /**
-         * bluetooth HCI snoop log configuration
-         * @hide
-         */
-        public static final String BLUETOOTH_HCI_LOG =
-                "bluetooth_hci_log";
-
-        /**
          * @deprecated Use {@link android.provider.Settings.Global#DEVICE_PROVISIONED} instead
          */
         @Deprecated
@@ -9003,6 +8996,12 @@
         public static final String
                 BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX = "bluetooth_a2dp_src_priority_";
         /** {@hide} */
+        public static final String BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX =
+                "bluetooth_a2dp_supports_optional_codecs_";
+        /** {@hide} */
+        public static final String BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX =
+                "bluetooth_a2dp_optional_codecs_enabled_";
+        /** {@hide} */
         public static final String
                 BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX = "bluetooth_input_device_priority_";
         /** {@hide} */
@@ -9269,6 +9268,25 @@
         }
 
         /**
+         * Get the key that retrieves a bluetooth a2dp device's ability to support optional codecs.
+         * @hide
+         */
+        public static final String getBluetoothA2dpSupportsOptionalCodecsKey(String address) {
+            return BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX +
+                    address.toUpperCase(Locale.ROOT);
+        }
+
+        /**
+         * Get the key that retrieves whether a bluetooth a2dp device should have optional codecs
+         * enabled.
+         * @hide
+         */
+        public static final String getBluetoothA2dpOptionalCodecsEnabledKey(String address) {
+            return BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX +
+                    address.toUpperCase(Locale.ROOT);
+        }
+
+        /**
          * Get the key that retrieves a bluetooth Input Device's priority.
          * @hide
          */
@@ -10419,6 +10437,15 @@
         public static final String MAX_NOTIFICATION_ENQUEUE_RATE = "max_notification_enqueue_rate";
 
         /**
+         * Displays toasts when an app posts a notification that does not specify a valid channel.
+         *
+         * The value 1 - enable, 0 - disable
+         * @hide
+         */
+        public static final String SHOW_NOTIFICATION_CHANNEL_WARNINGS =
+                "show_notification_channel_warnings";
+
+        /**
          * Whether cell is enabled/disabled
          * @hide
          */
diff --git a/core/java/android/provider/TimeZoneRulesDataContract.java b/core/java/android/provider/TimeZoneRulesDataContract.java
new file mode 100644
index 0000000..19e914b
--- /dev/null
+++ b/core/java/android/provider/TimeZoneRulesDataContract.java
@@ -0,0 +1,114 @@
+/*
+ * 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 android.provider;
+
+import android.net.Uri;
+
+/**
+ * A set of constants for implementing a time zone data content provider, which is used by the time
+ * zone updater application.
+ *
+ * @hide
+ */
+// TODO(nfuller): Expose necessary APIs for OEMs with @SystemApi. http://b/31008728
+public final class TimeZoneRulesDataContract {
+
+    private TimeZoneRulesDataContract() {}
+
+    /**
+     * The authority that <em>must</em> be used for the time zone data content provider.
+     * To be accepted by the time zone updater application it <em>must</em> be exposed by the
+     * package specified in the config_timeZoneRulesDataPackage config value.
+     */
+    public static final String AUTHORITY = "com.android.timezone";
+
+    /** A content:// style uri to the authority for the time zone data content provider */
+    private static final Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
+
+    /**
+     * The content:// style URI for determining what type of update is available.
+     *
+     * <p>The URI can be queried using
+     * {@link android.content.ContentProvider#query(Uri, String[], String, String[], String)};
+     * the result will be a cursor with a single row. If the {@link #COLUMN_OPERATION}
+     * column is {@link #OPERATION_INSTALL} then see {@link #DATA_URI} for how to obtain the
+     * binary data.
+     */
+    public static final Uri OPERATION_URI = Uri.withAppendedPath(AUTHORITY_URI, "operation");
+
+    /**
+     * The {@code String} column of the {@link #OPERATION_URI} that provides an int specifying the
+     * type of operation to perform. See {@link #OPERATION_NO_OP}, {@link #OPERATION_UNINSTALL} and
+     * {@link #OPERATION_INSTALL}.
+     */
+    public static final String COLUMN_OPERATION = "operation";
+
+    /**
+     * An operation type used when the time zone rules on device should be left as they are.
+     * This is not expected to be used in normal operation but a safe result in the event of an
+     * error that cannot be recovered from.
+     */
+    public static final String OPERATION_NO_OP = "NOOP";
+
+    /**
+     * An operation type used when the current time zone rules on device should be uninstalled,
+     * returning to the values held in the system partition.
+     */
+    public static final String OPERATION_UNINSTALL = "UNINSTALL";
+
+    /**
+     * An operation type used when the current time zone rules on device should be replaced by
+     * a new set obtained via the {@link android.content.ContentProvider#openFile(Uri, String)}
+     * method.
+     */
+    public static final String OPERATION_INSTALL = "INSTALL";
+
+    /**
+     * The {@code nullable int} column of the {@link #OPERATION_URI} that describes the major
+     * version of the distro to be installed.
+     * Only non-null if {@link #COLUMN_OPERATION} contains {@link #OPERATION_INSTALL}.
+     */
+    public static final String COLUMN_DISTRO_MAJOR_VERSION = "distro_major_version";
+
+    /**
+     * The {@code nullable int} column of the {@link #OPERATION_URI} that describes the minor
+     * version of the distro to be installed.
+     * Only non-null if {@link #COLUMN_OPERATION} contains {@link #OPERATION_INSTALL}.
+     */
+    public static final String COLUMN_DISTRO_MINOR_VERSION = "distro_minor_version";
+
+    /**
+     * The {@code nullable String} column of the {@link #OPERATION_URI} that describes the IANA
+     * rules version of the distro to be installed.
+     * Only non-null if {@link #COLUMN_OPERATION} contains {@link #OPERATION_INSTALL}.
+     */
+    public static final String COLUMN_RULES_VERSION = "rules_version";
+
+    /**
+     * The {@code nullable int} column of the {@link #OPERATION_URI} that describes the revision
+     * number of the distro to be installed.
+     * Only non-null if {@link #COLUMN_OPERATION} contains {@link #OPERATION_INSTALL}.
+     */
+    public static final String COLUMN_REVISION = "revision";
+
+    /**
+     * The content:// style URI for obtaining time zone bundle data.
+     *
+     * <p>Use {@link android.content.ContentProvider#openFile(Uri, String)} with "r" mode.
+     */
+    public static final Uri DATA_URI = Uri.withAppendedPath(AUTHORITY_URI, "data");
+}
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 88d17ef..5fd9458 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -15,6 +15,7 @@
  */
 package android.service.autofill;
 
+import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.os.RemoteException;
@@ -156,6 +157,7 @@
      *
      * <strong>NOTE: </strong>if overridden, it must call {@code super.onCreate()}.
      */
+    @CallSuper
     @Override
     public void onCreate() {
         super.onCreate();
diff --git a/core/java/android/service/autofill/SaveInfo.java b/core/java/android/service/autofill/SaveInfo.java
index 277c622..9487760 100644
--- a/core/java/android/service/autofill/SaveInfo.java
+++ b/core/java/android/service/autofill/SaveInfo.java
@@ -174,6 +174,7 @@
                SAVE_DATA_TYPE_PASSWORD,
                SAVE_DATA_TYPE_ADDRESS,
                SAVE_DATA_TYPE_CREDIT_CARD,
+               SAVE_DATA_TYPE_USERNAME,
                SAVE_DATA_TYPE_EMAIL_ADDRESS})
     @Retention(RetentionPolicy.SOURCE)
     @interface SaveDataType{}
diff --git a/core/java/android/service/voice/VoiceInteractionService.java b/core/java/android/service/voice/VoiceInteractionService.java
index 479c9e2..fbc6fc6 100644
--- a/core/java/android/service/voice/VoiceInteractionService.java
+++ b/core/java/android/service/voice/VoiceInteractionService.java
@@ -262,7 +262,8 @@
      * @param keyphrase The keyphrase that's being used, for example "Hello Android".
      * @param locale The locale for which the enrollment needs to be performed.
      * @param callback The callback to notify of detection events.
-     * @return An always-on hotword detector for the given keyphrase and locale.
+     * @return An always-on hotword detector for the given keyphrase and locale. Is null if the
+     * keyphrase and locale is not supported.
      */
     public final AlwaysOnHotwordDetector createAlwaysOnHotwordDetector(
             String keyphrase, Locale locale, AlwaysOnHotwordDetector.Callback callback) {
@@ -272,8 +273,10 @@
         synchronized (mLock) {
             // Allow only one concurrent recognition via the APIs.
             safelyShutdownHotwordDetector();
-            mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
-                    mKeyphraseEnrollmentInfo, mInterface, mSystemService);
+            if (isKeyphraseAndLocaleSupportedForHotword(keyphrase, locale)) {
+                mHotwordDetector = new AlwaysOnHotwordDetector(keyphrase, locale, callback,
+                        mKeyphraseEnrollmentInfo, mInterface, mSystemService);
+            }
         }
         return mHotwordDetector;
     }
@@ -287,6 +290,20 @@
         return mKeyphraseEnrollmentInfo;
     }
 
+    /**
+      * Checks if a given keyphrase and locale are supported to create an
+      * {@link AlwaysOnHotwordDetector}.
+      *
+      * @return true if the keyphrase and locale combination is supported, false otherwise.
+      * @hide
+      */
+    public final boolean isKeyphraseAndLocaleSupportedForHotword(String keyphrase, Locale locale) {
+        if (mKeyphraseEnrollmentInfo == null) {
+            return false;
+        }
+        return mKeyphraseEnrollmentInfo.getKeyphraseMetadata(keyphrase, locale) != null;
+    }
+
     private void safelyShutdownHotwordDetector() {
         try {
             synchronized (mLock) {
diff --git a/core/java/android/service/vr/IVrManager.aidl b/core/java/android/service/vr/IVrManager.aidl
index 8b2d0c6..9b37a65 100644
--- a/core/java/android/service/vr/IVrManager.aidl
+++ b/core/java/android/service/vr/IVrManager.aidl
@@ -16,7 +16,7 @@
 
 package android.service.vr;
 
-import android.app.CompatibilityDisplayProperties;
+import android.app.Vr2dDisplayProperties;
 import android.service.vr.IVrStateCallbacks;
 import android.service.vr.IPersistentVrStateCallbacks;
 
@@ -68,16 +68,16 @@
     void setPersistentVrModeEnabled(in boolean enabled);
 
     /**
-     * Sets the resolution and DPI of the compatibility virtual display used to display
+     * Sets the resolution and DPI of the vr2d virtual display used to display
      * 2D applications in VR mode.
      *
      * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
      *
-     * @param compatDisplayProperties Compatibitlity display properties to be set for
+     * @param vr2dDisplayProperties Vr2d display properties to be set for
      * the VR virtual display
      */
-    void setCompatibilityDisplayProperties(
-            in CompatibilityDisplayProperties compatDisplayProperties);
+    void setVr2dDisplayProperties(
+            in Vr2dDisplayProperties vr2dDisplayProperties);
 
     /**
      * Return current virtual display id.
@@ -85,18 +85,6 @@
      * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display
      * currently, else return the display id of the virtual display
      */
-    int getCompatibilityDisplayId();
-
-    /**
-     * Initiate connection for system controller data.
-     *
-     * @param fd Controller data file descriptor.
-     */
-    void connectController(in FileDescriptor fd);
-
-    /**
-     * Sever connection for system controller data.
-     */
-    void disconnectController();
+    int getVr2dDisplayId();
 }
 
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 081deeb..585f882 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -1520,6 +1520,18 @@
     /**
      * Returns a CharSequence concatenating the specified CharSequences,
      * retaining their spans if any.
+     *
+     * If there are no parameters, an empty string will be returned.
+     *
+     * If the number of parameters is exactly one, that parameter is returned as output, even if it
+     * is null.
+     *
+     * If the number of parameters is at least two, any null CharSequence among the parameters is
+     * treated as if it was the string <code>"null"</code>.
+     *
+     * If there are paragraph spans in the source CharSequences that satisfy paragraph boundary
+     * requirements in the sources but would no longer satisfy them in the concatenated
+     * CharSequence, they may get extended in the resulting CharSequence or not retained.
      */
     public static CharSequence concat(CharSequence... text) {
         if (text.length == 0) {
@@ -1531,35 +1543,29 @@
         }
 
         boolean spanned = false;
-        for (int i = 0; i < text.length; i++) {
-            if (text[i] instanceof Spanned) {
+        for (CharSequence piece : text) {
+            if (piece instanceof Spanned) {
                 spanned = true;
                 break;
             }
         }
 
-        StringBuilder sb = new StringBuilder();
-        for (int i = 0; i < text.length; i++) {
-            sb.append(text[i]);
-        }
-
-        if (!spanned) {
+        if (spanned) {
+            final SpannableStringBuilder ssb = new SpannableStringBuilder();
+            for (CharSequence piece : text) {
+                // If a piece is null, we append the string "null" for compatibility with the
+                // behavior of StringBuilder and the behavior of the concat() method in earlier
+                // versions of Android.
+                ssb.append(piece == null ? "null" : piece);
+            }
+            return new SpannedString(ssb);
+        } else {
+            final StringBuilder sb = new StringBuilder();
+            for (CharSequence piece : text) {
+                sb.append(piece);
+            }
             return sb.toString();
         }
-
-        SpannableString ss = new SpannableString(sb);
-        int off = 0;
-        for (int i = 0; i < text.length; i++) {
-            int len = text[i].length();
-
-            if (text[i] instanceof Spanned) {
-                copySpansFrom((Spanned) text[i], 0, len, Object.class, ss, off);
-            }
-
-            off += len;
-        }
-
-        return new SpannedString(ss);
     }
 
     /**
@@ -1921,6 +1927,22 @@
         return false;
     }
 
+    /**
+     * If the {@code charSequence} is instance of {@link Spanned}, creates a new copy and
+     * {@link NoCopySpan}'s are removed from the copy. Otherwise the given {@code charSequence} is
+     * returned as it is.
+     *
+     * @hide
+     */
+    @Nullable
+    public static CharSequence trimNoCopySpans(@Nullable CharSequence charSequence) {
+        if (charSequence != null && charSequence instanceof Spanned) {
+            // SpannableStringBuilder copy constructor trims NoCopySpans.
+            return new SpannableStringBuilder(charSequence);
+        }
+        return charSequence;
+    }
+
     private static Object sLock = new Object();
 
     private static char[] sTemp = null;
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index ea2434e..8405d9e 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
@@ -768,6 +770,36 @@
     }
 
     /**
+     * Returns true if input device is enabled.
+     * @return Whether the input device is enabled.
+     */
+    public boolean isEnabled() {
+        return InputManager.getInstance().isInputDeviceEnabled(mId);
+    }
+
+    /**
+     * Enables the input device.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE)
+    @TestApi
+    public void enable() {
+        InputManager.getInstance().enableInputDevice(mId);
+    }
+
+    /**
+     * Disables the input device.
+     *
+     * @hide
+     */
+    @RequiresPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE)
+    @TestApi
+    public void disable() {
+        InputManager.getInstance().disableInputDevice(mId);
+    }
+
+    /**
      * Reports whether the device has a built-in microphone.
      * @return Whether the device has a built-in microphone.
      */
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e9e9d7c..ff42ff6 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6844,7 +6844,7 @@
         if (isAutofillable() && isAttachedToWindow()) {
             AutofillManager afm = getAutofillManager();
             if (afm != null) {
-                if (enter && hasWindowFocus() && isFocused()) {
+                if (enter && hasWindowFocus() && isFocused() && isVisibleToUser()) {
                     afm.notifyViewEntered(this);
                 } else if (!hasWindowFocus() || !isFocused()) {
                     afm.notifyViewExited(this);
@@ -7237,44 +7237,53 @@
 
         RectF position = mAttachInfo.mTmpTransformRect;
         position.set(0, 0, mRight - mLeft, mBottom - mTop);
+        mapRectFromViewToScreenCoords(position, clipToParent);
+        outRect.set(Math.round(position.left), Math.round(position.top),
+                Math.round(position.right), Math.round(position.bottom));
+    }
 
+    /**
+     * Map a rectangle from view-relative coordinates to screen-relative coordinates
+     *
+     * @param rect The rectangle to be mapped
+     * @param clipToParent Whether to clip child bounds to the parent ones.
+     * @hide
+     */
+    public void mapRectFromViewToScreenCoords(RectF rect, boolean clipToParent) {
         if (!hasIdentityMatrix()) {
-            getMatrix().mapRect(position);
+            getMatrix().mapRect(rect);
         }
 
-        position.offset(mLeft, mTop);
+        rect.offset(mLeft, mTop);
 
         ViewParent parent = mParent;
         while (parent instanceof View) {
             View parentView = (View) parent;
 
-            position.offset(-parentView.mScrollX, -parentView.mScrollY);
+            rect.offset(-parentView.mScrollX, -parentView.mScrollY);
 
             if (clipToParent) {
-                position.left = Math.max(position.left, 0);
-                position.top = Math.max(position.top, 0);
-                position.right = Math.min(position.right, parentView.getWidth());
-                position.bottom = Math.min(position.bottom, parentView.getHeight());
+                rect.left = Math.max(rect.left, 0);
+                rect.top = Math.max(rect.top, 0);
+                rect.right = Math.min(rect.right, parentView.getWidth());
+                rect.bottom = Math.min(rect.bottom, parentView.getHeight());
             }
 
             if (!parentView.hasIdentityMatrix()) {
-                parentView.getMatrix().mapRect(position);
+                parentView.getMatrix().mapRect(rect);
             }
 
-            position.offset(parentView.mLeft, parentView.mTop);
+            rect.offset(parentView.mLeft, parentView.mTop);
 
             parent = parentView.mParent;
         }
 
         if (parent instanceof ViewRootImpl) {
             ViewRootImpl viewRootImpl = (ViewRootImpl) parent;
-            position.offset(0, -viewRootImpl.mCurScrollY);
+            rect.offset(0, -viewRootImpl.mCurScrollY);
         }
 
-        position.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
-
-        outRect.set(Math.round(position.left), Math.round(position.top),
-                Math.round(position.right), Math.round(position.bottom));
+        rect.offset(mAttachInfo.mWindowLeft, mAttachInfo.mWindowTop);
     }
 
     /**
@@ -7295,7 +7304,7 @@
      * fills in all data that can be inferred from the view itself.
      */
     public void onProvideStructure(ViewStructure structure) {
-        onProvideStructureForAssistOrAutofill(structure, false);
+        onProvideStructureForAssistOrAutofill(structure, false, 0);
     }
 
     /**
@@ -7309,6 +7318,9 @@
      *   <li>It must set fields such {@link ViewStructure#setText(CharSequence)},
      * {@link ViewStructure#setAutofillOptions(CharSequence[])},
      * or {@link ViewStructure#setWebDomain(String)}.
+     *   <li> The {@code left} and {@code top} values set in
+     * {@link ViewStructure#setDimens(int, int, int, int, int, int)} need to be relative to the next
+     * {@link ViewGroup#isImportantForAutofill() included} parent in the structure.
      * </ul>
      *
      * @param structure Fill in with structured view data. The default implementation
@@ -7317,12 +7329,12 @@
      *
      * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
      */
-    public void onProvideAutofillStructure(ViewStructure structure, int flags) {
-        onProvideStructureForAssistOrAutofill(structure, true);
+    public void onProvideAutofillStructure(ViewStructure structure, @AutofillFlags int flags) {
+        onProvideStructureForAssistOrAutofill(structure, true, flags);
     }
 
     private void onProvideStructureForAssistOrAutofill(ViewStructure structure,
-            boolean forAutofill) {
+            boolean forAutofill, @AutofillFlags int flags) {
         final int id = mID;
         if (id != NO_ID && !isViewIdGenerated(id)) {
             String pkg, type, entry;
@@ -7350,11 +7362,37 @@
             }
         }
 
-        structure.setDimens(mLeft, mTop, mScrollX, mScrollY, mRight - mLeft, mBottom - mTop);
-        if (!hasIdentityMatrix()) {
-            structure.setTransformation(getMatrix());
+        int ignoredParentLeft = 0;
+        int ignoredParentTop = 0;
+        if (forAutofill && (flags & AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) {
+            View parentGroup = null;
+
+            ViewParent viewParent = getParent();
+            if (viewParent instanceof View) {
+                parentGroup = (View) viewParent;
+            }
+
+            while (parentGroup != null && !parentGroup.isImportantForAutofill()) {
+                ignoredParentLeft += parentGroup.mLeft;
+                ignoredParentTop += parentGroup.mTop;
+
+                viewParent = parentGroup.getParent();
+                if (viewParent instanceof View) {
+                    parentGroup = (View) viewParent;
+                } else {
+                    break;
+                }
+            }
         }
-        structure.setElevation(getZ());
+
+        structure.setDimens(ignoredParentLeft + mLeft, ignoredParentTop + mTop, mScrollX, mScrollY,
+                mRight - mLeft, mBottom - mTop);
+        if (!forAutofill) {
+            if (!hasIdentityMatrix()) {
+                structure.setTransformation(getMatrix());
+            }
+            structure.setElevation(getZ());
+        }
         structure.setVisibility(getVisibility());
         structure.setEnabled(isEnabled());
         if (isClickable()) {
@@ -7434,10 +7472,15 @@
      * <li>Call {@link AutofillManager#cancel()} ()} when the autofill context
      * of the view structure changed and you want the current autofill interaction if such
      * to be cancelled.
+     * <li> The {@code left} and {@code top} values set in
+     * {@link ViewStructure#setDimens(int, int, int, int, int, int)} need to be relative to the next
+     * {@link ViewGroup#isImportantForAutofill() included} parent in the structure.
      * </ol>
      *
      * @param structure Fill in with structured view data.
-     * @param flags optional flags (currently {@code 0}).
+     * @param flags optional flags.
+     *
+     * @see #AUTOFILL_FLAG_INCLUDE_NOT_IMPORTANT_VIEWS
      */
     public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
     }
@@ -7695,7 +7738,8 @@
     }
 
     private boolean isAutofillable() {
-        return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill();
+        return getAutofillType() != AUTOFILL_TYPE_NONE && isImportantForAutofill()
+                && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID;
     }
 
     private void populateVirtualStructure(ViewStructure structure,
@@ -7760,7 +7804,7 @@
      * {@link #onProvideVirtualStructure}.
      */
     public void dispatchProvideStructure(ViewStructure structure) {
-        dispatchProvideStructureForAssistOrAutofill(structure, false);
+        dispatchProvideStructureForAssistOrAutofill(structure, false, 0);
     }
 
     /**
@@ -7793,16 +7837,15 @@
      */
     public void dispatchProvideAutofillStructure(@NonNull ViewStructure structure,
             @AutofillFlags int flags) {
-        dispatchProvideStructureForAssistOrAutofill(structure, true);
+        dispatchProvideStructureForAssistOrAutofill(structure, true, flags);
     }
 
     private void dispatchProvideStructureForAssistOrAutofill(ViewStructure structure,
-            boolean forAutofill) {
+            boolean forAutofill, @AutofillFlags int flags) {
         if (forAutofill) {
             structure.setAutofillId(getAutofillId());
-            // NOTE: flags are not currently supported, hence 0
-            onProvideAutofillStructure(structure, 0);
-            onProvideAutofillVirtualStructure(structure, 0);
+            onProvideAutofillStructure(structure, flags);
+            onProvideAutofillVirtualStructure(structure, flags);
         } else if (!isAssistBlocked()) {
             onProvideStructure(structure);
             onProvideVirtualStructure(structure);
@@ -20419,9 +20462,10 @@
     @Nullable private Drawable getAutofilledDrawable() {
         // Lazily load the isAutofilled drawable.
         if (mAttachInfo.mAutofilledDrawable == null) {
-            TypedArray a = mContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR);
+            Context rootContext = getRootView().getContext();
+            TypedArray a = rootContext.getTheme().obtainStyledAttributes(AUTOFILL_HIGHLIGHT_ATTR);
             int attributeResourceId = a.getResourceId(0, 0);
-            mAttachInfo.mAutofilledDrawable = mContext.getDrawable(attributeResourceId);
+            mAttachInfo.mAutofilledDrawable = rootContext.getDrawable(attributeResourceId);
             a.recycle();
         }
 
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index f71589c..6bdc9ff 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -374,13 +374,6 @@
     public abstract Rect getTempRect();
 
     /**
-     * @deprecated - use {@link #setWebDomain(String)} instead.
-     * @hide
-     */
-    @Deprecated
-    public abstract void setUrl(String url);
-
-    /**
      * Sets the Web domain represented by this node.
      *
      * <p>Typically used when the view is a container for an HTML document.
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index a432d30..6dd8ecf 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -480,13 +480,6 @@
         public void onWindowFocusChanged(boolean hasFocus);
 
         /**
-         * @hide
-         */
-        default void onBeforeAttachedToWindow() {
-            // empty
-        }
-
-        /**
          * Called when the window has been attached to the window manager.
          * See {@link View#onAttachedToWindow() View.onAttachedToWindow()}
          * for more information.
diff --git a/core/java/android/view/WindowCallbackWrapper.java b/core/java/android/view/WindowCallbackWrapper.java
index 7018529..02c8945 100644
--- a/core/java/android/view/WindowCallbackWrapper.java
+++ b/core/java/android/view/WindowCallbackWrapper.java
@@ -109,11 +109,6 @@
     }
 
     @Override
-    public void onBeforeAttachedToWindow() {
-        mWrapped.onBeforeAttachedToWindow();
-    }
-
-    @Override
     public void onAttachedToWindow() {
         mWrapped.onAttachedToWindow();
     }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index d0133ed..c7151db 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -28,7 +28,6 @@
 import android.graphics.Rect;
 import android.metrics.LogMaker;
 import android.os.Bundle;
-import android.os.IBinder;
 import android.os.Parcelable;
 import android.os.RemoteException;
 import android.service.autofill.AutofillService;
@@ -38,7 +37,6 @@
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.View;
-import android.view.WindowManagerGlobal;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.logging.MetricsLogger;
@@ -47,6 +45,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
@@ -188,11 +187,11 @@
         boolean autofillCallbackRequestHideFillUi();
 
         /**
-         * Checks if the view is currently attached and visible.
+         * Checks if views are currently attached and visible.
          *
-         * @return {@code true} iff the view is attached or visible
+         * @return And array with {@code true} iff the view is attached or visible
          */
-        boolean getViewVisibility(int viewId);
+        @NonNull boolean[] getViewVisibility(@NonNull int[] viewId);
 
         /**
          * Checks is the client is currently visible as understood by autofill.
@@ -200,6 +199,15 @@
          * @return {@code true} if the client is currently visible
          */
         boolean isVisibleForAutofill();
+
+        /**
+         * Find views by traversing the hierarchies of the client.
+         *
+         * @param viewIds The accessibility ids of the views to find
+         *
+         * @return And array containing the views, or {@code null} if not found
+         */
+        @NonNull View[] findViewsByAccessibilityIdTraversal(@NonNull int[] viewIds);
     }
 
     /**
@@ -259,30 +267,6 @@
     }
 
     /**
-     * Set window future popup windows should be attached to.
-     *
-     * @param windowToken The window the popup windows should be attached to
-     *
-     * {@hide}
-     */
-    public void onAttachedToWindow(@NonNull IBinder windowToken) {
-        if (!hasAutofillFeature()) {
-            return;
-        }
-        synchronized (mLock) {
-            if (mSessionId == NO_SESSION) {
-                return;
-            }
-
-            try {
-                mService.setWindow(mSessionId, windowToken);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Could not attach window to session " + mSessionId);
-            }
-        }
-    }
-
-    /**
      * Called once the client becomes visible.
      *
      * @see AutofillClient#isVisibleForAutofill()
@@ -292,7 +276,7 @@
     public void onVisibleForAutofill() {
         synchronized (mLock) {
             if (mEnabled && mSessionId != NO_SESSION && mTrackedViews != null) {
-                mTrackedViews.onVisibleForAutofill();
+                mTrackedViews.onVisibleForAutofillLocked();
             }
         }
     }
@@ -406,7 +390,7 @@
 
                 if (mSessionId == NO_SESSION) {
                     // Starts new session.
-                    startSessionLocked(id, view.getWindowToken(), null, value, flags);
+                    startSessionLocked(id, null, value, flags);
                 } else {
                     // Update focus on existing session.
                     updateSessionLocked(id, null, value, ACTION_VIEW_ENTERED, flags);
@@ -484,7 +468,7 @@
 
                 if (mSessionId == NO_SESSION) {
                     // Starts new session.
-                    startSessionLocked(id, view.getWindowToken(), bounds, null, flags);
+                    startSessionLocked(id, bounds, null, flags);
                 } else {
                     // Update focus on existing session.
                     updateSessionLocked(id, bounds, null, ACTION_VIEW_ENTERED, flags);
@@ -725,15 +709,15 @@
         return new AutofillId(parent.getAccessibilityViewId(), childId);
     }
 
-    private void startSessionLocked(@NonNull AutofillId id, @NonNull IBinder windowToken,
-            @NonNull Rect bounds, @NonNull AutofillValue value, int flags) {
+    private void startSessionLocked(@NonNull AutofillId id, @NonNull Rect bounds,
+            @NonNull AutofillValue value, int flags) {
         if (sVerbose) {
             Log.v(TAG, "startSessionLocked(): id=" + id + ", bounds=" + bounds + ", value=" + value
                     + ", flags=" + flags);
         }
 
         try {
-            mSessionId = mService.startSession(mContext.getActivityToken(), windowToken,
+            mSessionId = mService.startSession(mContext.getActivityToken(),
                     mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
                     mCallback != null, flags, mContext.getOpPackageName());
             final AutofillClient client = getClientLocked();
@@ -855,9 +839,9 @@
         }
     }
 
-    private void requestShowFillUi(int sessionId, IBinder windowToken, AutofillId id, int width,
-            int height, Rect anchorBounds, IAutofillWindowPresenter presenter) {
-        final View anchor = findAchorView(windowToken, id);
+    private void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
+            Rect anchorBounds, IAutofillWindowPresenter presenter) {
+        final View anchor = findView(id);
         if (anchor == null) {
             return;
         }
@@ -930,27 +914,27 @@
         }
     }
 
-    private void autofill(int sessionId, IBinder windowToken, List<AutofillId> ids,
-            List<AutofillValue> values) {
+    private void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
         synchronized (mLock) {
             if (sessionId != mSessionId) {
                 return;
             }
 
-            final View root = WindowManagerGlobal.getInstance().getWindowView(windowToken);
-            if (root == null) {
+            final AutofillClient client = getClientLocked();
+            if (client == null) {
                 return;
             }
 
             final int itemCount = ids.size();
             int numApplied = 0;
             ArrayMap<View, SparseArray<AutofillValue>> virtualValues = null;
+            final View[] views = client.findViewsByAccessibilityIdTraversal(getViewIds(ids));
 
             for (int i = 0; i < itemCount; i++) {
                 final AutofillId id = ids.get(i);
                 final AutofillValue value = values.get(i);
                 final int viewId = id.getViewId();
-                final View view = root.findViewByAccessibilityIdTraversal(viewId);
+                final View view = views[i];
                 if (view == null) {
                     Log.w(TAG, "autofill(): no View with id " + viewId);
                     continue;
@@ -1022,8 +1006,11 @@
         }
     }
 
-    private void requestHideFillUi(int sessionId, IBinder windowToken, AutofillId id) {
-        final View anchor = findAchorView(windowToken, id);
+    private void requestHideFillUi(int sessionId, AutofillId id) {
+        final View anchor = findView(id);
+        if (anchor == null) {
+            return;
+        }
 
         AutofillCallback callback = null;
         synchronized (mLock) {
@@ -1049,8 +1036,11 @@
         }
     }
 
-    private void notifyNoFillUi(int sessionId, IBinder windowToken, AutofillId id) {
-        final View anchor = findAchorView(windowToken, id);
+    private void notifyNoFillUi(int sessionId, AutofillId id) {
+        final View anchor = findView(id);
+        if (anchor == null) {
+            return;
+        }
 
         AutofillCallback callback = null;
         synchronized (mLock) {
@@ -1070,18 +1060,38 @@
         }
     }
 
-    private View findAchorView(IBinder windowToken, AutofillId id) {
-        final View root = WindowManagerGlobal.getInstance().getWindowView(windowToken);
-        if (root == null) {
-            Log.w(TAG, "no window with token " + windowToken);
+    /**
+     * Get an array of viewIds from a List of {@link AutofillId}.
+     *
+     * @param autofillIds The autofill ids to convert
+     *
+     * @return The array of viewIds.
+     */
+    @NonNull private int[] getViewIds(@NonNull List<AutofillId> autofillIds) {
+        final int numIds = autofillIds.size();
+        final int[] viewIds = new int[numIds];
+        for (int i = 0; i < numIds; i++) {
+            viewIds[i] = autofillIds.get(i).getViewId();
+        }
+
+        return viewIds;
+    }
+
+    /**
+     * Find a single view by its id.
+     *
+     * @param autofillId The autofill id of the view
+     *
+     * @return The view or {@code null} if view was not found
+     */
+    private View findView(@NonNull AutofillId autofillId) {
+        final AutofillClient client = getClientLocked();
+
+        if (client == null) {
             return null;
         }
-        final View view = root.findViewByAccessibilityIdTraversal(id.getViewId());
-        if (view == null) {
-            Log.w(TAG, "no view with id " + id);
-            return null;
-        }
-        return view;
+
+        return client.findViewsByAccessibilityIdTraversal(new int[]{autofillId.getViewId()})[0];
     }
 
     /** @hide */
@@ -1160,22 +1170,26 @@
          *
          * @param trackedIds The views to be tracked
          */
-        TrackedViews(@NonNull List<AutofillId> trackedIds) {
+        TrackedViews(List<AutofillId> trackedIds) {
             mVisibleTrackedIds = null;
             mInvisibleTrackedIds = null;
 
             AutofillClient client = getClientLocked();
-            if (trackedIds != null) {
-                int numIds = trackedIds.size();
+            if (trackedIds != null && client != null) {
+                final boolean[] isVisible;
+
+                if (client.isVisibleForAutofill()) {
+                    isVisible = client.getViewVisibility(getViewIds(trackedIds));
+                } else {
+                    // All false
+                    isVisible = new boolean[trackedIds.size()];
+                }
+
+                final int numIds = trackedIds.size();
                 for (int i = 0; i < numIds; i++) {
-                    AutofillId id = trackedIds.get(i);
+                    final AutofillId id = trackedIds.get(i);
 
-                    boolean isVisible = true;
-                    if (client != null && client.isVisibleForAutofill()) {
-                        isVisible = client.getViewVisibility(id.getViewId());
-                    }
-
-                    if (isVisible) {
+                    if (isVisible[i]) {
                         mVisibleTrackedIds = addToSet(mVisibleTrackedIds, id);
                     } else {
                         mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id);
@@ -1233,16 +1247,23 @@
          *
          * @see AutofillClient#isVisibleForAutofill()
          */
-        void onVisibleForAutofill() {
-            // The visibility of the views might have changed while the client was not started,
+        void onVisibleForAutofillLocked() {
+            // The visibility of the views might have changed while the client was not be visible,
             // hence update the visibility state for all views.
             AutofillClient client = getClientLocked();
             ArraySet<AutofillId> updatedVisibleTrackedIds = null;
             ArraySet<AutofillId> updatedInvisibleTrackedIds = null;
             if (client != null) {
                 if (mInvisibleTrackedIds != null) {
-                    for (AutofillId id : mInvisibleTrackedIds) {
-                        if (client.getViewVisibility(id.getViewId())) {
+                    final ArrayList<AutofillId> orderedInvisibleIds =
+                            new ArrayList<>(mInvisibleTrackedIds);
+                    final boolean[] isVisible = client.getViewVisibility(
+                            getViewIds(orderedInvisibleIds));
+
+                    final int numInvisibleTrackedIds = orderedInvisibleIds.size();
+                    for (int i = 0; i < numInvisibleTrackedIds; i++) {
+                        final AutofillId id = orderedInvisibleIds.get(i);
+                        if (isVisible[i]) {
                             updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id);
 
                             if (sDebug) {
@@ -1255,8 +1276,16 @@
                 }
 
                 if (mVisibleTrackedIds != null) {
-                    for (AutofillId id : mVisibleTrackedIds) {
-                        if (client.getViewVisibility(id.getViewId())) {
+                    final ArrayList<AutofillId> orderedVisibleIds =
+                            new ArrayList<>(mVisibleTrackedIds);
+                    final boolean[] isVisible = client.getViewVisibility(
+                            getViewIds(orderedVisibleIds));
+
+                    final int numVisibleTrackedIds = orderedVisibleIds.size();
+                    for (int i = 0; i < numVisibleTrackedIds; i++) {
+                        final AutofillId id = orderedVisibleIds.get(i);
+
+                        if (isVisible[i]) {
                             updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id);
                         } else {
                             updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id);
@@ -1355,12 +1384,11 @@
         }
 
         @Override
-        public void autofill(int sessionId, IBinder windowToken, List<AutofillId> ids,
-                List<AutofillValue> values) {
+        public void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
                 afm.mContext.getMainThreadHandler().post(
-                        () -> afm.autofill(sessionId, windowToken, ids, values));
+                        () -> afm.autofill(sessionId, ids, values));
             }
         }
 
@@ -1374,31 +1402,30 @@
         }
 
         @Override
-        public void requestShowFillUi(int sessionId, IBinder windowToken, AutofillId id,
-                int width, int height, Rect anchorBounds, IAutofillWindowPresenter presenter) {
+        public void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
+                Rect anchorBounds, IAutofillWindowPresenter presenter) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
                 afm.mContext.getMainThreadHandler().post(
-                        () -> afm.requestShowFillUi(sessionId, windowToken, id, width, height,
-                                anchorBounds, presenter));
+                        () -> afm.requestShowFillUi(sessionId, id, width, height, anchorBounds,
+                                presenter));
             }
         }
 
         @Override
-        public void requestHideFillUi(int sessionId, IBinder windowToken, AutofillId id) {
+        public void requestHideFillUi(int sessionId, AutofillId id) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
                 afm.mContext.getMainThreadHandler().post(
-                        () -> afm.requestHideFillUi(sessionId, windowToken, id));
+                        () -> afm.requestHideFillUi(sessionId, id));
             }
         }
 
         @Override
-        public void notifyNoFillUi(int sessionId, IBinder windowToken, AutofillId id) {
+        public void notifyNoFillUi(int sessionId, AutofillId id) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.mContext.getMainThreadHandler().post(
-                        () -> afm.notifyNoFillUi(sessionId, windowToken, id));
+                afm.mContext.getMainThreadHandler().post(() -> afm.notifyNoFillUi(sessionId, id));
             }
         }
 
diff --git a/core/java/android/view/autofill/AutofillValue.java b/core/java/android/view/autofill/AutofillValue.java
index b57dab5..3beae11 100644
--- a/core/java/android/view/autofill/AutofillValue.java
+++ b/core/java/android/view/autofill/AutofillValue.java
@@ -26,6 +26,7 @@
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
 import android.view.View;
 
 import com.android.internal.util.Preconditions;
@@ -257,7 +258,8 @@
      * <p>See {@link View#AUTOFILL_TYPE_TEXT} for more info.
      */
     public static AutofillValue forText(@Nullable CharSequence value) {
-        return value == null ? null : new AutofillValue(AUTOFILL_TYPE_TEXT, value);
+        return value == null ? null : new AutofillValue(AUTOFILL_TYPE_TEXT,
+                TextUtils.trimNoCopySpans(value));
     }
 
     /**
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index f28d8ba..4193a3c 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -32,12 +32,11 @@
 interface IAutoFillManager {
     // Returns flags: FLAG_ADD_CLIENT_ENABLED | FLAG_ADD_CLIENT_DEBUG | FLAG_ADD_CLIENT_VERBOSE
     int addClient(in IAutoFillManagerClient client, int userId);
-    int startSession(IBinder activityToken, IBinder windowToken, in IBinder appCallback,
-            in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
-            boolean hasCallback, int flags, String packageName);
+    int startSession(IBinder activityToken, in IBinder appCallback, in AutofillId autoFillId,
+            in Rect bounds, in AutofillValue value, int userId, boolean hasCallback, int flags,
+            String packageName);
     FillEventHistory getFillEventHistory();
     boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
-    void setWindow(int sessionId, in IBinder windowToken);
     void updateSession(int sessionId, in AutofillId id, in Rect bounds,
             in AutofillValue value, int action, int flags, int userId);
     void finishSession(int sessionId, int userId);
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index aef98b7..825d311 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -40,8 +40,7 @@
     /**
       * Autofills the activity with the contents of a dataset.
       */
-    void autofill(int sessionId, in IBinder windowToken, in List<AutofillId> ids,
-            in List<AutofillValue> values);
+    void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
 
     /**
       * Authenticates a fill response or a data set.
@@ -58,18 +57,18 @@
     /**
      * Requests showing the fill UI.
      */
-    void requestShowFillUi(int sessionId, in IBinder windowToken, in AutofillId id, int width,
-            int height, in Rect anchorBounds, in IAutofillWindowPresenter presenter);
+    void requestShowFillUi(int sessionId, in AutofillId id, int width, int height,
+    in Rect anchorBounds, in IAutofillWindowPresenter presenter);
 
     /**
      * Requests hiding the fill UI.
      */
-    void requestHideFillUi(int sessionId, in IBinder windowToken, in AutofillId id);
+    void requestHideFillUi(int sessionId, in AutofillId id);
 
     /**
      * Notifies no fill UI will be shown.
      */
-    void notifyNoFillUi(int sessionId, in IBinder windowToken, in AutofillId id);
+    void notifyNoFillUi(int sessionId, in AutofillId id);
 
     /**
      * Starts the provided intent sender
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 209ff09..7362c70 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -102,7 +102,9 @@
                         string, selectionStartIndex, selectionEndIndex);
                 final int start = startEnd[0];
                 final int end = startEnd[1];
-                if (start >= 0 && end <= string.length() && start <= end) {
+                if (start <= end
+                        && start >= 0 && end <= string.length()
+                        && start <= selectionStartIndex && end >= selectionEndIndex) {
                     final TextSelection.Builder tsBuilder = new TextSelection.Builder(start, end);
                     final SmartSelection.ClassificationResult[] results =
                             smartSelection.classifyText(
@@ -144,9 +146,6 @@
                     final TextClassification classificationResult =
                             createClassificationResult(
                                     results, string.subSequence(startIndex, endIndex));
-                    // TODO: Added this log for debug only. Remove before release.
-                    Log.d(LOG_TAG, String.format(
-                            "Classification type: %s", classificationResult));
                     return classificationResult;
                 }
             }
@@ -377,11 +376,6 @@
                 && Linkify.sUrlMatchFilter.acceptMatch(text, start, end)) {
             flag |= SmartSelection.HINT_FLAG_URL;
         }
-        // TODO: Added this log for debug only. Remove before release.
-        Log.d(LOG_TAG, String.format("Email hint: %b",
-                (flag & SmartSelection.HINT_FLAG_EMAIL) != 0));
-        Log.d(LOG_TAG, String.format("Url hint: %b",
-                (flag & SmartSelection.HINT_FLAG_URL) != 0));
         return flag;
     }
 
diff --git a/core/java/android/view/textservice/SpellCheckerSession.java b/core/java/android/view/textservice/SpellCheckerSession.java
index 2e2056c..779eefb 100644
--- a/core/java/android/view/textservice/SpellCheckerSession.java
+++ b/core/java/android/view/textservice/SpellCheckerSession.java
@@ -29,6 +29,8 @@
 import com.android.internal.textservice.ITextServicesManager;
 import com.android.internal.textservice.ITextServicesSessionListener;
 
+import dalvik.system.CloseGuard;
+
 import java.util.LinkedList;
 import java.util.Queue;
 
@@ -98,7 +100,7 @@
     private final SpellCheckerSessionListener mSpellCheckerSessionListener;
     private final SpellCheckerSessionListenerImpl mSpellCheckerSessionListenerImpl;
 
-    private boolean mIsUsed;
+    private final CloseGuard mGuard = CloseGuard.get();
 
     /** Handler that will execute the main tasks */
     private final Handler mHandler = new Handler() {
@@ -128,8 +130,9 @@
         mSpellCheckerSessionListenerImpl = new SpellCheckerSessionListenerImpl(mHandler);
         mInternalListener = new InternalListener(mSpellCheckerSessionListenerImpl);
         mTextServicesManager = tsm;
-        mIsUsed = true;
         mSpellCheckerSessionListener = listener;
+
+        mGuard.open("finishSession");
     }
 
     /**
@@ -160,7 +163,7 @@
      * checker.
      */
     public void close() {
-        mIsUsed = false;
+        mGuard.close();
         try {
             mSpellCheckerSessionListenerImpl.close();
             mTextServicesManager.finishSpellCheckerService(mSpellCheckerSessionListenerImpl);
@@ -542,11 +545,14 @@
 
     @Override
     protected void finalize() throws Throwable {
-        super.finalize();
-        if (mIsUsed) {
-            Log.e(TAG, "SpellCheckerSession was not finished properly." +
-                    "You should call finishSession() when you finished to use a spell checker.");
-            close();
+        try {
+            // Note that mGuard will be null if the constructor threw.
+            if (mGuard != null) {
+                mGuard.warnIfOpen();
+                close();
+            }
+        } finally {
+            super.finalize();
         }
     }
 
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 52c82a7..ecb25fe 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -98,7 +98,7 @@
  * invoke the Browser application with a URL Intent rather than show it
  * with a WebView. For example:
  * <pre>
- * Uri uri = Uri.parse("http://www.example.com");
+ * Uri uri = Uri.parse("https://www.example.com");
  * Intent intent = new Intent(Intent.ACTION_VIEW, uri);
  * startActivity(intent);
  * </pre>
@@ -116,7 +116,7 @@
  * <pre>
  * // Simplest usage: note that an exception will NOT be thrown
  * // if there is an error loading this page (see below).
- * webview.loadUrl("http://slashdot.org/");
+ * webview.loadUrl("https://example.com/");
  *
  * // OR, you can also load from an HTML string:
  * String summary = "&lt;html>&lt;body>You scored &lt;b>192&lt;/b> points.&lt;/body>&lt;/html>";
@@ -175,7 +175,7 @@
  *   }
  * });
  *
- * webview.loadUrl("http://developer.android.com/");
+ * webview.loadUrl("https://developer.android.com/");
  * </pre>
  *
  * <h3>Zoom</h3>
@@ -2705,7 +2705,7 @@
      * <p>Example2: an IFRAME tag.
      *
      * <pre class="prettyprint">
-     *    <iframe src="http://example.com/login"/>
+     *    <iframe src="https://example.com/login"/>
      * </pre>
      *
      * <p>Would map to:
@@ -2714,7 +2714,7 @@
      *     int index = structure.addChildCount(1);
      *     ViewStructure iframe = structure.newChildFor(index);
      *     iframe.setHtmlInfo(child.newHtmlInfoBuilder("iframe")
-     *         .addAttribute("url", "http://example.com/login")
+     *         .addAttribute("url", "https://example.com/login")
      *         .build());
      * </pre>
      */
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index ad3a99d..b0d6395 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -1404,6 +1404,11 @@
             // or double-clicks that could "dismiss" the floating toolbar.
             int delay = ViewConfiguration.getDoubleTapTimeout();
             mTextView.postDelayed(mShowFloatingToolbar, delay);
+
+            // This classifies the text and most likely returns before the toolbar is actually
+            // shown. If not, it will update the toolbar with the result when classification
+            // returns. We would rather not wait for a long running classification process.
+            invalidateActionModeAsync();
         }
     }
 
@@ -1853,7 +1858,7 @@
             mInsertionPointCursorController.invalidateHandle();
         }
         if (mTextActionMode != null) {
-            invalidateActionModeAsync();
+            invalidateActionMode();
         }
     }
 
@@ -1945,12 +1950,12 @@
                 if (mRestartActionModeOnNextRefresh) {
                     // To avoid distraction, newly start action mode only when selection action
                     // mode is being restarted.
-                    startSelectionActionMode();
+                    startSelectionActionModeAsync(false);
                 }
             } else if (selectionController == null || !selectionController.isActive()) {
                 // Insertion action mode is active. Avoid dismissing the selection.
                 stopTextActionModeWithPreservingSelection();
-                startSelectionActionMode();
+                startSelectionActionModeAsync(false);
             } else {
                 mTextActionMode.invalidateContentRect();
             }
@@ -2004,15 +2009,8 @@
     /**
      * Asynchronously starts a selection action mode using the TextClassifier.
      */
-    void startSelectionActionModeAsync() {
-        getSelectionActionModeHelper().startActionModeAsync();
-    }
-
-    /**
-     * Synchronously starts a selection action mode without the TextClassifier.
-     */
-    void startSelectionActionMode() {
-        getSelectionActionModeHelper().startActionMode();
+    void startSelectionActionModeAsync(boolean adjustSelection) {
+        getSelectionActionModeHelper().startActionModeAsync(adjustSelection);
     }
 
     /**
@@ -2022,6 +2020,15 @@
         getSelectionActionModeHelper().invalidateActionModeAsync();
     }
 
+    /**
+     * Synchronously invalidates an action mode without the TextClassifier.
+     */
+    private void invalidateActionMode() {
+        if (mTextActionMode != null) {
+            mTextActionMode.invalidate();
+        }
+    }
+
     private SelectionActionModeHelper getSelectionActionModeHelper() {
         if (mSelectionActionModeHelper == null) {
             mSelectionActionModeHelper = new SelectionActionModeHelper(this);
@@ -2075,7 +2082,7 @@
         }
         if (mTextActionMode != null) {
             // Text action mode is already started
-            invalidateActionModeAsync();
+            invalidateActionMode();
             return false;
         }
 
@@ -4703,7 +4710,7 @@
             }
             positionAtCursorOffset(offset, false);
             if (mTextActionMode != null) {
-                invalidateActionModeAsync();
+                invalidateActionMode();
             }
         }
 
@@ -4787,7 +4794,7 @@
             }
             updateDrawable();
             if (mTextActionMode != null) {
-                invalidateActionModeAsync();
+                invalidateActionMode();
             }
         }
 
@@ -5414,13 +5421,8 @@
                     resetDragAcceleratorState();
 
                     if (mTextView.hasSelection()) {
-                        // Do not invoke the text assistant if this was a drag selection.
-                        if (mHaventMovedEnoughToStartDrag) {
-                            startSelectionActionModeAsync();
-                        } else {
-                            startSelectionActionMode();
-                        }
-
+                        // Drag selection should not be adjusted by the text classifier.
+                        startSelectionActionModeAsync(mHaventMovedEnoughToStartDrag);
                     }
                     break;
             }
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index 1457d02..569fe01 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -49,7 +49,6 @@
 import android.widget.RemoteViews.RemoteView;
 
 import com.android.internal.R;
-import com.android.internal.util.Preconditions;
 
 import com.google.android.collect.Lists;
 
@@ -336,11 +335,6 @@
      * @param isSelectable whether the item is selectable
      */
     public void addHeaderView(View v, Object data, boolean isSelectable) {
-        Preconditions.checkState(
-                v.getParent() == null,
-                "The specified child already has a parent. "
-                + "You must call removeView() on the child's parent first.");
-
         final FixedViewInfo info = new FixedViewInfo();
         info.view = v;
         info.data = data;
@@ -435,11 +429,6 @@
      * @param isSelectable true if the footer view can be selected
      */
     public void addFooterView(View v, Object data, boolean isSelectable) {
-        Preconditions.checkState(
-                v.getParent() == null,
-                "The specified child already has a parent. "
-                + "You must call removeView() on the child's parent first.");
-
         final FixedViewInfo info = new FixedViewInfo();
         info.view = v;
         info.data = data;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index c9d172f..16a1087 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -65,7 +65,7 @@
                 textView.getTextClassifier(), textView.getText(), 0, 1, textView.getTextLocales());
     }
 
-    public void startActionModeAsync() {
+    public void startActionModeAsync(boolean adjustSelection) {
         cancelAsyncTask();
         if (isNoOpTextClassifier() || !hasSelection()) {
             // No need to make an async call for a no-op TextClassifier.
@@ -74,16 +74,16 @@
         } else {
             resetTextClassificationHelper();
             mTextClassificationAsyncTask = new TextClassificationAsyncTask(
-                    mEditor.getTextView(), TIMEOUT_DURATION,
-                    mTextClassificationHelper::suggestSelection, this::startActionMode)
+                    mEditor.getTextView(),
+                    TIMEOUT_DURATION,
+                    adjustSelection
+                            ? mTextClassificationHelper::suggestSelection
+                            : mTextClassificationHelper::classifyText,
+                    this::startActionMode)
                     .execute();
         }
     }
 
-    public void startActionMode() {
-        startActionMode(null);
-    }
-
     public void invalidateActionModeAsync() {
         cancelAsyncTask();
         if (isNoOpTextClassifier() || !hasSelection()) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 242dcf5..bf44f62 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10136,7 +10136,11 @@
             if (lineCount <= 1) {
                 // Simple case: this is a single line.
                 final CharSequence text = getText();
-                structure.setText(text, getSelectionStart(), getSelectionEnd());
+                if (forAutofill) {
+                    structure.setText(text);
+                } else {
+                    structure.setText(text, getSelectionStart(), getSelectionEnd());
+                }
             } else {
                 // Complex case: multi-line, could be scrolled or within a scroll container
                 // so some lines are not visible.
@@ -10172,9 +10176,11 @@
                 if (expandedBottomLine >= lineCount) {
                     expandedBottomLine = lineCount - 1;
                 }
+
                 // Convert lines into character offsets.
                 int expandedTopChar = layout.getLineStart(expandedTopLine);
                 int expandedBottomChar = layout.getLineEnd(expandedBottomLine);
+
                 // Take into account selection -- if there is a selection, we need to expand
                 // the text we are returning to include that selection.
                 final int selStart = getSelectionStart();
@@ -10187,48 +10193,57 @@
                         expandedBottomChar = selEnd;
                     }
                 }
+
                 // Get the text and trim it to the range we are reporting.
                 CharSequence text = getText();
                 if (expandedTopChar > 0 || expandedBottomChar < text.length()) {
                     text = text.subSequence(expandedTopChar, expandedBottomChar);
                 }
-                structure.setText(text, selStart - expandedTopChar, selEnd - expandedTopChar);
-                final int[] lineOffsets = new int[bottomLine - topLine + 1];
-                final int[] lineBaselines = new int[bottomLine - topLine + 1];
-                final int baselineOffset = getBaselineOffset();
-                for (int i = topLine; i <= bottomLine; i++) {
-                    lineOffsets[i - topLine] = layout.getLineStart(i);
-                    lineBaselines[i - topLine] = layout.getLineBaseline(i) + baselineOffset;
+
+                if (forAutofill) {
+                    structure.setText(text);
+                } else {
+                    structure.setText(text, selStart - expandedTopChar, selEnd - expandedTopChar);
+
+                    final int[] lineOffsets = new int[bottomLine - topLine + 1];
+                    final int[] lineBaselines = new int[bottomLine - topLine + 1];
+                    final int baselineOffset = getBaselineOffset();
+                    for (int i = topLine; i <= bottomLine; i++) {
+                        lineOffsets[i - topLine] = layout.getLineStart(i);
+                        lineBaselines[i - topLine] = layout.getLineBaseline(i) + baselineOffset;
+                    }
+                    structure.setTextLines(lineOffsets, lineBaselines);
                 }
-                structure.setTextLines(lineOffsets, lineBaselines);
             }
 
-            // Extract style information that applies to the TextView as a whole.
-            int style = 0;
-            int typefaceStyle = getTypefaceStyle();
-            if ((typefaceStyle & Typeface.BOLD) != 0) {
-                style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
-            }
-            if ((typefaceStyle & Typeface.ITALIC) != 0) {
-                style |= AssistStructure.ViewNode.TEXT_STYLE_ITALIC;
-            }
+            if (!forAutofill) {
+                // Extract style information that applies to the TextView as a whole.
+                int style = 0;
+                int typefaceStyle = getTypefaceStyle();
+                if ((typefaceStyle & Typeface.BOLD) != 0) {
+                    style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
+                }
+                if ((typefaceStyle & Typeface.ITALIC) != 0) {
+                    style |= AssistStructure.ViewNode.TEXT_STYLE_ITALIC;
+                }
 
-            // Global styles can also be set via TextView.setPaintFlags().
-            int paintFlags = mTextPaint.getFlags();
-            if ((paintFlags & Paint.FAKE_BOLD_TEXT_FLAG) != 0) {
-                style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
-            }
-            if ((paintFlags & Paint.UNDERLINE_TEXT_FLAG) != 0) {
-                style |= AssistStructure.ViewNode.TEXT_STYLE_UNDERLINE;
-            }
-            if ((paintFlags & Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
-                style |= AssistStructure.ViewNode.TEXT_STYLE_STRIKE_THRU;
-            }
+                // Global styles can also be set via TextView.setPaintFlags().
+                int paintFlags = mTextPaint.getFlags();
+                if ((paintFlags & Paint.FAKE_BOLD_TEXT_FLAG) != 0) {
+                    style |= AssistStructure.ViewNode.TEXT_STYLE_BOLD;
+                }
+                if ((paintFlags & Paint.UNDERLINE_TEXT_FLAG) != 0) {
+                    style |= AssistStructure.ViewNode.TEXT_STYLE_UNDERLINE;
+                }
+                if ((paintFlags & Paint.STRIKE_THRU_TEXT_FLAG) != 0) {
+                    style |= AssistStructure.ViewNode.TEXT_STYLE_STRIKE_THRU;
+                }
 
-            // TextView does not have its own text background color. A background is either part
-            // of the View (and can be any drawable) or a BackgroundColorSpan inside the text.
-            structure.setTextStyle(getTextSize(), getCurrentTextColor(),
-                    AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style);
+                // TextView does not have its own text background color. A background is either part
+                // of the View (and can be any drawable) or a BackgroundColorSpan inside the text.
+                structure.setTextStyle(getTextSize(), getCurrentTextColor(),
+                        AssistStructure.ViewNode.TEXT_COLOR_UNDEFINED /* bgColor */, style);
+            }
         }
         structure.setHint(getHint());
         structure.setInputType(getInputType());
@@ -10385,14 +10400,13 @@
                     positionInfoStartIndex + positionInfoLength,
                     viewportToContentHorizontalOffset(), viewportToContentVerticalOffset());
             CursorAnchorInfo cursorAnchorInfo = builder.setMatrix(null).build();
-            int[] locationOnScreen = getLocationOnScreen();
             for (int i = 0; i < positionInfoLength; i++) {
                 int flags = cursorAnchorInfo.getCharacterBoundsFlags(positionInfoStartIndex + i);
                 if ((flags & FLAG_HAS_VISIBLE_REGION) == FLAG_HAS_VISIBLE_REGION) {
                     RectF bounds = cursorAnchorInfo
                             .getCharacterBounds(positionInfoStartIndex + i);
                     if (bounds != null) {
-                        bounds.offset(locationOnScreen[0], locationOnScreen[1]);
+                        mapRectFromViewToScreenCoords(bounds, true);
                         boundingRects[i] = bounds;
                     }
                 }
@@ -10579,7 +10593,7 @@
                         Selection.setSelection((Spannable) text, start, end);
                         // Make sure selection mode is engaged.
                         if (mEditor != null) {
-                            mEditor.startSelectionActionMode();
+                            mEditor.startSelectionActionModeAsync(false);
                         }
                         return true;
                     }
diff --git a/core/java/com/android/internal/inputmethod/LocaleUtils.java b/core/java/com/android/internal/inputmethod/LocaleUtils.java
index b18f83c..eeb3854 100644
--- a/core/java/com/android/internal/inputmethod/LocaleUtils.java
+++ b/core/java/com/android/internal/inputmethod/LocaleUtils.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.icu.util.ULocale;
 import android.os.LocaleList;
+import android.text.TextUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -41,7 +42,7 @@
     /**
      * Calculates a matching score for the single desired locale.
      *
-     * @see LocaleUtils#calculateMatchingScore(ULocale, LocaleList, byte[])
+     * @see LocaleUtils#filterByLanguage(List, LocaleExtractor, LocaleList, ArrayList)
      *
      * @param supported The locale supported by IME subtype.
      * @param desired The locale preferred by user.
@@ -72,48 +73,6 @@
         return 3;
     }
 
-    /**
-     * Calculates a matching score for the desired locale list.
-     *
-     * <p>The supported locale gets a matching score of 3 if all language, script and country of the
-     * supported locale matches with the desired locale.  The supported locale gets a matching
-     * score of 2 if the language and script of the supported locale matches with the desired
-     * locale. The supported locale gets a matching score of 1 if only language of the supported
-     * locale matches with the desired locale.  The supported locale gets a matching score of 0 if
-     * the language of the supported locale doesn't match with the desired locale.</p>
-     *
-     * @param supported The locale supported by IME subtyle.
-     * @param desired The locale list preferred by user. Typically system locale list.
-     * @param out The output buffer to be stored the individual score for the desired language list.
-     * The length of {@code out} must be same as the length of {@code desired} language list.
-     * @return {@code false} if supported locale doesn't match with any desired locale list.
-     * Otherwise {@code true}.
-     */
-    private static boolean calculateMatchingScore(@NonNull final ULocale supported,
-            @NonNull final LocaleList desired, @NonNull byte[] out) {
-        if (desired.isEmpty()) {
-            return false;
-        }
-
-        boolean allZeros = true;
-        final int N = desired.size();
-        for (int i = 0; i < N; ++i) {
-            final Locale locale = desired.get(i);
-
-            if (!locale.getLanguage().equals(supported.getLanguage())) {
-                // TODO: cache the result of addLikelySubtags if it is slow.
-                out[i] = 0;
-            } else {
-                out[i] = calculateMatchingSubScore(
-                        supported, ULocale.addLikelySubtags(ULocale.forLocale(locale)));
-                if (allZeros && out[i] != 0) {
-                    allZeros = false;
-                }
-            }
-        }
-        return !allZeros;
-    }
-
     private static final class ScoreEntry implements Comparable<ScoreEntry> {
         public int mIndex = -1;
         @NonNull public final byte[] mScore;  // matching score of the i-th system languages.
@@ -175,17 +134,17 @@
     /**
      * Filters the given items based on language preferences.
      *
-     * <p>For each language found in {@code preferredLanguages}, this method tries to copy at most
+     * <p>For each language found in {@code preferredLocales}, this method tries to copy at most
      * one best-match item from {@code source} to {@code dest}.  For example, if
-     * {@code "en-GB", "ja", "en-AU", "fr-CA", "en-IN"} is specified to {@code preferredLanguages},
+     * {@code "en-GB", "ja", "en-AU", "fr-CA", "en-IN"} is specified to {@code preferredLocales},
      * this method tries to copy at most one English locale, at most one Japanese, and at most one
      * French locale from {@code source} to {@code dest}.  Here the best matching English locale
      * will be searched from {@code source} based on matching score. For the score design, see
-     * {@link LocaleUtils#calculateMatchingScore(ULocale, LocaleList, byte[])}</p>
+     * {@link LocaleUtils#calculateMatchingSubScore(ULocale, ULocale)}</p>
      *
      * @param sources Source items to be filtered.
      * @param extractor Type converter from the source items to {@link Locale} object.
-     * @param preferredLanguages Ordered list of locales with which the input items will be
+     * @param preferredLocales Ordered list of locales with which the input items will be
      * filtered.
      * @param dest Destination into which the filtered items will be added.
      * @param <T> Type of the data items.
@@ -194,17 +153,43 @@
     public static <T> void filterByLanguage(
             @NonNull List<T> sources,
             @NonNull LocaleExtractor<T> extractor,
-            @NonNull LocaleList preferredLanguages,
+            @NonNull LocaleList preferredLocales,
             @NonNull ArrayList<T> dest) {
+        if (preferredLocales.isEmpty()) {
+            return;
+        }
+
+        final int numPreferredLocales = preferredLocales.size();
         final HashMap<String, ScoreEntry> scoreboard = new HashMap<>();
-        final byte[] score = new byte[preferredLanguages.size()];
+        final byte[] score = new byte[numPreferredLocales];
+        final ULocale[] preferredULocaleCache = new ULocale[numPreferredLocales];
 
         final int sourceSize = sources.size();
         for (int i = 0; i < sourceSize; ++i) {
             final Locale locale = extractor.get(sources.get(i));
-            if (locale == null ||
-                    !calculateMatchingScore(ULocale.addLikelySubtags(ULocale.forLocale(locale)),
-                            preferredLanguages, score)) {
+            if (locale == null) {
+                continue;
+            }
+
+            boolean canSkip = true;
+            for (int j = 0; j < numPreferredLocales; ++j) {
+                final Locale preferredLocale = preferredLocales.get(j);
+                if (!TextUtils.equals(locale.getLanguage(), preferredLocale.getLanguage())) {
+                    score[j] = 0;
+                    continue;
+                }
+                if (preferredULocaleCache[j] == null) {
+                    preferredULocaleCache[j] = ULocale.addLikelySubtags(
+                            ULocale.forLocale(preferredLocale));
+                }
+                score[j] = calculateMatchingSubScore(
+                        preferredULocaleCache[j],
+                        ULocale.addLikelySubtags(ULocale.forLocale(locale)));
+                if (canSkip && score[j] != 0) {
+                    canSkip = false;
+                }
+            }
+            if (canSkip) {
                 continue;
             }
 
diff --git a/core/java/com/android/internal/policy/DecorView.java b/core/java/com/android/internal/policy/DecorView.java
index 80b6b08..1b83708 100644
--- a/core/java/com/android/internal/policy/DecorView.java
+++ b/core/java/com/android/internal/policy/DecorView.java
@@ -1498,7 +1498,6 @@
 
         final Window.Callback cb = mWindow.getCallback();
         if (cb != null && !mWindow.isDestroyed() && mFeatureId < 0) {
-            cb.onBeforeAttachedToWindow();
             cb.onAttachedToWindow();
         }
 
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 73886a7..91bc681 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -583,4 +583,8 @@
         }
         return size - leftIdx;
     }
+
+    public static @NonNull String[] defeatNullable(@Nullable String[] val) {
+        return (val != null) ? val : EmptyArray.STRING;
+    }
 }
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 2c97f8b..cd41f9e 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -286,6 +286,38 @@
     }
 
     /**
+     * Finds a suitable alpha such that there's enough contrast.
+     *
+     * @param color the color to start searching from.
+     * @param backgroundColor the color to ensure contrast against.
+     * @param minRatio the minimum contrast ratio required.
+     * @return the same color as {@param color} with potentially modified alpha to meet contrast
+     */
+    public static int findAlphaToMeetContrast(int color, int backgroundColor, double minRatio) {
+        int fg = color;
+        int bg = backgroundColor;
+        if (ColorUtilsFromCompat.calculateContrast(fg, bg) >= minRatio) {
+            return color;
+        }
+        int startAlpha = Color.alpha(color);
+        int r = Color.red(color);
+        int g = Color.green(color);
+        int b = Color.blue(color);
+
+        int low = startAlpha, high = 255;
+        for (int i = 0; i < 15 && high - low > 0; i++) {
+            final int alpha = (low + high) / 2;
+            fg = Color.argb(alpha, r, g, b);
+            if (ColorUtilsFromCompat.calculateContrast(fg, bg) > minRatio) {
+                high = alpha;
+            } else {
+                low = alpha;
+            }
+        }
+        return Color.argb(high, r, g, b);
+    }
+
+    /**
      * Finds a suitable color such that there's enough contrast.
      *
      * @param color the color to start searching from.
@@ -373,19 +405,19 @@
      * color for the Notification's action and header text.
      *
      * @param notificationColor the color of the notification or {@link Notification#COLOR_DEFAULT}
+     * @param backgroundColor the background color to ensure the contrast against.
      * @return a color of the same hue with enough contrast against the backgrounds.
      */
-    public static int resolveContrastColor(Context context, int notificationColor) {
+    public static int resolveContrastColor(Context context, int notificationColor,
+            int backgroundColor) {
         final int resolvedColor = resolveColor(context, notificationColor);
 
         final int actionBg = context.getColor(
                 com.android.internal.R.color.notification_action_list);
-        final int notiBg = context.getColor(
-                com.android.internal.R.color.notification_material_background_color);
 
         int color = resolvedColor;
         color = NotificationColorUtil.ensureLargeTextContrast(color, actionBg);
-        color = NotificationColorUtil.ensureTextContrast(color, notiBg);
+        color = NotificationColorUtil.ensureTextContrast(color, backgroundColor);
 
         if (color != resolvedColor) {
             if (DEBUG){
@@ -394,7 +426,7 @@
                                 + " and %s (over background) by changing #%s to %s",
                         context.getPackageName(),
                         NotificationColorUtil.contrastChange(resolvedColor, color, actionBg),
-                        NotificationColorUtil.contrastChange(resolvedColor, color, notiBg),
+                        NotificationColorUtil.contrastChange(resolvedColor, color, backgroundColor),
                         Integer.toHexString(resolvedColor), Integer.toHexString(color)));
             }
         }
@@ -502,6 +534,13 @@
     }
 
     /**
+     * Composite two potentially translucent colors over each other and returns the result.
+     */
+    public static int compositeColors(int foreground, int background) {
+        return ColorUtilsFromCompat.compositeColors(foreground, background);
+    }
+
+    /**
      * Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
      */
     private static class ColorUtilsFromCompat {
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
new file mode 100644
index 0000000..0dc46ed
--- /dev/null
+++ b/core/jni/Android.bp
@@ -0,0 +1,286 @@
+cc_library_shared {
+    name: "libandroid_runtime",
+
+    cflags: [
+        "-Wno-unused-parameter",
+        "-Wno-non-virtual-dtor",
+        "-Wno-maybe-uninitialized",
+        "-Wno-parentheses",
+
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DEGL_EGLEXT_PROTOTYPES",
+
+        "-DU_USING_ICU_NAMESPACE=0",
+
+        "-Wall",
+        "-Werror",
+        "-Wno-error=deprecated-declarations",
+        "-Wunused",
+        "-Wunreachable-code",
+
+        // necessary for Clang as the GL bindings need to turn
+        // off a GCC warning that Clang doesn't know.
+        "-Wno-unknown-pragmas",
+
+        // TODO: Linear blending should be enabled by default, but we are
+        // TODO: making it an opt-in while it's a work in progress
+        //"-DANDROID_ENABLE_LINEAR_BLENDING",
+    ],
+
+    cppflags: ["-Wno-conversion-null"],
+
+    srcs: [
+        "AndroidRuntime.cpp",
+        "com_android_internal_content_NativeLibraryHelper.cpp",
+        "com_google_android_gles_jni_EGLImpl.cpp",
+        "com_google_android_gles_jni_GLImpl.cpp", // TODO: .arm
+        "android_app_Activity.cpp",
+        "android_app_ApplicationLoaders.cpp",
+        "android_app_NativeActivity.cpp",
+        "android_app_admin_SecurityLog.cpp",
+        "android_opengl_EGL14.cpp",
+        "android_opengl_EGLExt.cpp",
+        "android_opengl_GLES10.cpp",
+        "android_opengl_GLES10Ext.cpp",
+        "android_opengl_GLES11.cpp",
+        "android_opengl_GLES11Ext.cpp",
+        "android_opengl_GLES20.cpp",
+        "android_opengl_GLES30.cpp",
+        "android_opengl_GLES31.cpp",
+        "android_opengl_GLES31Ext.cpp",
+        "android_opengl_GLES32.cpp",
+        "android_database_CursorWindow.cpp",
+        "android_database_SQLiteCommon.cpp",
+        "android_database_SQLiteConnection.cpp",
+        "android_database_SQLiteGlobal.cpp",
+        "android_database_SQLiteDebug.cpp",
+        "android_graphics_drawable_AnimatedVectorDrawable.cpp",
+        "android_graphics_drawable_VectorDrawable.cpp",
+        "android_view_DisplayEventReceiver.cpp",
+        "android_view_DisplayListCanvas.cpp",
+        "android_view_HardwareLayer.cpp",
+        "android_view_InputChannel.cpp",
+        "android_view_InputDevice.cpp",
+        "android_view_InputEventReceiver.cpp",
+        "android_view_InputEventSender.cpp",
+        "android_view_InputQueue.cpp",
+        "android_view_KeyCharacterMap.cpp",
+        "android_view_KeyEvent.cpp",
+        "android_view_MotionEvent.cpp",
+        "android_view_PointerIcon.cpp",
+        "android_view_RenderNode.cpp",
+        "android_view_RenderNodeAnimator.cpp",
+        "android_view_Surface.cpp",
+        "android_view_SurfaceControl.cpp",
+        "android_view_SurfaceSession.cpp",
+        "android_view_TextureView.cpp",
+        "android_view_ThreadedRenderer.cpp",
+        "android_view_VelocityTracker.cpp",
+        "android_text_AndroidCharacter.cpp",
+        "android_text_AndroidBidi.cpp",
+        "android_text_StaticLayout.cpp",
+        "android_os_Debug.cpp",
+        "android_os_GraphicsEnvironment.cpp",
+        "android_os_HwBinder.cpp",
+        "android_os_HwBlob.cpp",
+        "android_os_HwParcel.cpp",
+        "android_os_HwRemoteBinder.cpp",
+        "android_os_MemoryFile.cpp",
+        "android_os_MessageQueue.cpp",
+        "android_os_Parcel.cpp",
+        "android_os_SELinux.cpp",
+        "android_os_seccomp.cpp",
+        "android_os_SystemClock.cpp",
+        "android_os_SystemProperties.cpp",
+        "android_os_Trace.cpp",
+        "android_os_UEventObserver.cpp",
+        "android_os_VintfObject.cpp",
+        "android_os_VintfRuntimeInfo.cpp",
+        "android_net_LocalSocketImpl.cpp",
+        "android_net_NetUtils.cpp",
+        "android_net_TrafficStats.cpp",
+        "android_nio_utils.cpp",
+        "android_util_AssetManager.cpp",
+        "android_util_Binder.cpp",
+        "android_util_EventLog.cpp",
+        "android_util_MemoryIntArray.cpp",
+        "android_util_Log.cpp",
+        "android_util_PathParser.cpp",
+        "android_util_Process.cpp",
+        "android_util_StringBlock.cpp",
+        "android_util_XmlBlock.cpp",
+        "android_util_jar_StrictJarFile.cpp",
+        "android_graphics_Canvas.cpp",
+        "android_graphics_Picture.cpp",
+        "android/graphics/Bitmap.cpp",
+        "android/graphics/BitmapFactory.cpp",
+        "android/graphics/Camera.cpp",
+        "android/graphics/CanvasProperty.cpp",
+        "android/graphics/ColorFilter.cpp",
+        "android/graphics/DrawFilter.cpp",
+        "android/graphics/FontFamily.cpp",
+        "android/graphics/FontUtils.cpp",
+        "android/graphics/CreateJavaOutputStreamAdaptor.cpp",
+        "android/graphics/GIFMovie.cpp",
+        "android/graphics/GraphicBuffer.cpp",
+        "android/graphics/Graphics.cpp",
+        "android/graphics/HarfBuzzNGFaceSkia.cpp",
+        "android/graphics/Interpolator.cpp",
+        "android/graphics/MaskFilter.cpp",
+        "android/graphics/Matrix.cpp",
+        "android/graphics/Movie.cpp",
+        "android/graphics/MovieImpl.cpp",
+        "android/graphics/NinePatch.cpp",
+        "android/graphics/NinePatchPeeker.cpp",
+        "android/graphics/Paint.cpp",
+        "android/graphics/Path.cpp",
+        "android/graphics/PathMeasure.cpp",
+        "android/graphics/PathEffect.cpp",
+        "android/graphics/Picture.cpp",
+        "android/graphics/BitmapRegionDecoder.cpp",
+        "android/graphics/Region.cpp",
+        "android/graphics/Shader.cpp",
+        "android/graphics/SurfaceTexture.cpp",
+        "android/graphics/Typeface.cpp",
+        "android/graphics/Utils.cpp",
+        "android/graphics/YuvToJpegEncoder.cpp",
+        "android/graphics/pdf/PdfDocument.cpp",
+        "android/graphics/pdf/PdfEditor.cpp",
+        "android/graphics/pdf/PdfRenderer.cpp",
+        "android/graphics/pdf/PdfUtils.cpp",
+        "android_media_AudioRecord.cpp",
+        "android_media_AudioSystem.cpp",
+        "android_media_AudioTrack.cpp",
+        "android_media_DeviceCallback.cpp",
+        "android_media_JetPlayer.cpp",
+        "android_media_RemoteDisplay.cpp",
+        "android_media_ToneGenerator.cpp",
+        "android_hardware_Camera.cpp",
+        "android_hardware_camera2_CameraMetadata.cpp",
+        "android_hardware_camera2_legacy_LegacyCameraDevice.cpp",
+        "android_hardware_camera2_legacy_PerfMeasurement.cpp",
+        "android_hardware_camera2_DngCreator.cpp",
+        "android_hardware_HardwareBuffer.cpp",
+        "android_hardware_Radio.cpp",
+        "android_hardware_SensorManager.cpp",
+        "android_hardware_SerialPort.cpp",
+        "android_hardware_SoundTrigger.cpp",
+        "android_hardware_UsbDevice.cpp",
+        "android_hardware_UsbDeviceConnection.cpp",
+        "android_hardware_UsbRequest.cpp",
+        "android_hardware_location_ActivityRecognitionHardware.cpp",
+        "android_util_FileObserver.cpp",
+        "android/opengl/poly_clip.cpp", // TODO: .arm
+        "android/opengl/util.cpp",
+        "android_server_NetworkManagementSocketTagger.cpp",
+        "android_server_Watchdog.cpp",
+        "android_ddm_DdmHandleNativeHeap.cpp",
+        "android_backup_BackupDataInput.cpp",
+        "android_backup_BackupDataOutput.cpp",
+        "android_backup_FileBackupHelperBase.cpp",
+        "android_backup_BackupHelperDispatcher.cpp",
+        "android_app_backup_FullBackup.cpp",
+        "android_content_res_ObbScanner.cpp",
+        "android_content_res_Configuration.cpp",
+        "android_animation_PropertyValuesHolder.cpp",
+        "com_android_internal_net_NetworkStatsFactory.cpp",
+        "com_android_internal_os_FuseAppLoop.cpp",
+        "com_android_internal_os_PathClassLoaderFactory.cpp",
+        "com_android_internal_os_Zygote.cpp",
+        "com_android_internal_util_VirtualRefBasePtr.cpp",
+        "com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp",
+        "hwbinder/EphemeralStorage.cpp",
+        "fd_utils.cpp",
+    ],
+
+    include_dirs: [
+        // we need to access the private Bionic header
+        // <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
+        "bionic/libc/private",
+
+        "external/skia/include/private",
+        "external/skia/src/codec",
+        "external/skia/src/core",
+        "external/skia/src/effects",
+        "external/skia/src/image",
+        "external/skia/src/images",
+        "frameworks/base/media/jni",
+        "libcore/include",
+        "system/media/camera/include",
+        "system/media/private/camera/include",
+    ],
+
+    static_libs: [
+        "libgif",
+        "libseccomp_policy",
+        "libselinux",
+        "libcrypto",
+        "libgrallocusage",
+    ],
+
+    shared_libs: [
+        "libmemtrack",
+        "libandroidfw",
+        "libappfuse",
+        "libbase",
+        "libnativehelper",
+        "liblog",
+        "libcutils",
+        "libdebuggerd_client",
+        "libutils",
+        "libbinder",
+        "libui",
+        "libgui",
+        "libsensor",
+        "libinput",
+        "libcamera_client",
+        "libcamera_metadata",
+        "libskia",
+        "libsqlite",
+        "libEGL",
+        "libGLESv1_CM",
+        "libGLESv2",
+        "libvulkan",
+        "libziparchive",
+        "libETC1",
+        "libhardware",
+        "libhardware_legacy",
+        "libselinux",
+        "libicuuc",
+        "libmedia",
+        "libaudioclient",
+        "libjpeg",
+        "libusbhost",
+        "libharfbuzz_ng",
+        "libz",
+        "libpdfium",
+        "libimg_utils",
+        "libnetd_client",
+        "libradio",
+        "libsoundtrigger",
+        "libminikin",
+        "libprocessgroup",
+        "libnativebridge",
+        "libradio_metadata",
+        "libnativeloader",
+        "libmemunreachable",
+        "libhidlbase",
+        "libhidltransport",
+        "libhwbinder",
+        "libvintf",
+        "libnativewindow",
+
+        "libhwui",
+        "libdl",
+    ],
+
+    local_include_dirs: ["android/graphics"],
+    export_include_dirs: ["include"],
+    export_shared_lib_headers: [
+        // AndroidRuntime.h depends on nativehelper/jni.h
+        "libnativehelper",
+
+        // our headers include libnativewindow's public headers
+        "libnativewindow",
+    ],
+}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
deleted file mode 100644
index 77c72eb..0000000
--- a/core/jni/Android.mk
+++ /dev/null
@@ -1,322 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
-LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
-LOCAL_CFLAGS += -U__APPLE__
-LOCAL_CFLAGS += -Wno-unused-parameter
-LOCAL_CFLAGS += -Wno-non-virtual-dtor
-LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
-LOCAL_CPPFLAGS += -Wno-conversion-null
-
-ifeq ($(TARGET_ARCH), arm)
-    LOCAL_CFLAGS += -DPACKED="__attribute__ ((packed))"
-else
-    LOCAL_CFLAGS += -DPACKED=""
-endif
-
-ifneq ($(ENABLE_CPUSETS),)
-    LOCAL_CFLAGS += -DENABLE_CPUSETS
-endif
-
-# TODO: Linear blending should be enabled by default, but we are
-# TODO: making it an opt-in while it's a work in progress
-# TODO: The final test should be:
-# TODO: ifneq ($(TARGET_ENABLE_LINEAR_BLENDING),false)
-ifeq ($(TARGET_ENABLE_LINEAR_BLENDING),true)
-    LOCAL_CFLAGS += -DANDROID_ENABLE_LINEAR_BLENDING
-endif
-
-LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
-
-LOCAL_CFLAGS += -DU_USING_ICU_NAMESPACE=0
-
-LOCAL_SRC_FILES:= \
-    AndroidRuntime.cpp \
-    com_android_internal_content_NativeLibraryHelper.cpp \
-    com_google_android_gles_jni_EGLImpl.cpp \
-    com_google_android_gles_jni_GLImpl.cpp.arm \
-    android_app_Activity.cpp \
-    android_app_ApplicationLoaders.cpp \
-    android_app_NativeActivity.cpp \
-    android_app_admin_SecurityLog.cpp \
-    android_opengl_EGL14.cpp \
-    android_opengl_EGLExt.cpp \
-    android_opengl_GLES10.cpp \
-    android_opengl_GLES10Ext.cpp \
-    android_opengl_GLES11.cpp \
-    android_opengl_GLES11Ext.cpp \
-    android_opengl_GLES20.cpp \
-    android_opengl_GLES30.cpp \
-    android_opengl_GLES31.cpp \
-    android_opengl_GLES31Ext.cpp \
-    android_opengl_GLES32.cpp \
-    android_database_CursorWindow.cpp \
-    android_database_SQLiteCommon.cpp \
-    android_database_SQLiteConnection.cpp \
-    android_database_SQLiteGlobal.cpp \
-    android_database_SQLiteDebug.cpp \
-    android_graphics_drawable_AnimatedVectorDrawable.cpp \
-    android_graphics_drawable_VectorDrawable.cpp \
-    android_view_DisplayEventReceiver.cpp \
-    android_view_DisplayListCanvas.cpp \
-    android_view_HardwareLayer.cpp \
-    android_view_InputChannel.cpp \
-    android_view_InputDevice.cpp \
-    android_view_InputEventReceiver.cpp \
-    android_view_InputEventSender.cpp \
-    android_view_InputQueue.cpp \
-    android_view_KeyCharacterMap.cpp \
-    android_view_KeyEvent.cpp \
-    android_view_MotionEvent.cpp \
-    android_view_PointerIcon.cpp \
-    android_view_RenderNode.cpp \
-    android_view_RenderNodeAnimator.cpp \
-    android_view_Surface.cpp \
-    android_view_SurfaceControl.cpp \
-    android_view_SurfaceSession.cpp \
-    android_view_TextureView.cpp \
-    android_view_ThreadedRenderer.cpp \
-    android_view_VelocityTracker.cpp \
-    android_text_AndroidCharacter.cpp \
-    android_text_AndroidBidi.cpp \
-    android_text_StaticLayout.cpp \
-    android_os_Debug.cpp \
-    android_os_GraphicsEnvironment.cpp \
-    android_os_HwBinder.cpp \
-    android_os_HwBlob.cpp \
-    android_os_HwParcel.cpp \
-    android_os_HwRemoteBinder.cpp \
-    android_os_MemoryFile.cpp \
-    android_os_MessageQueue.cpp \
-    android_os_Parcel.cpp \
-    android_os_SELinux.cpp \
-    android_os_seccomp.cpp \
-    android_os_SystemClock.cpp \
-    android_os_SystemProperties.cpp \
-    android_os_Trace.cpp \
-    android_os_UEventObserver.cpp \
-    android_os_VintfObject.cpp \
-    android_os_VintfRuntimeInfo.cpp \
-    android_net_LocalSocketImpl.cpp \
-    android_net_NetUtils.cpp \
-    android_net_TrafficStats.cpp \
-    android_nio_utils.cpp \
-    android_util_AssetManager.cpp \
-    android_util_Binder.cpp \
-    android_util_EventLog.cpp \
-    android_util_MemoryIntArray.cpp \
-    android_util_Log.cpp \
-    android_util_PathParser.cpp \
-    android_util_Process.cpp \
-    android_util_StringBlock.cpp \
-    android_util_XmlBlock.cpp \
-    android_util_jar_StrictJarFile.cpp \
-    android_graphics_Canvas.cpp \
-    android_graphics_Picture.cpp \
-    android/graphics/Bitmap.cpp \
-    android/graphics/BitmapFactory.cpp \
-    android/graphics/Camera.cpp \
-    android/graphics/CanvasProperty.cpp \
-    android/graphics/ColorFilter.cpp \
-    android/graphics/DrawFilter.cpp \
-    android/graphics/FontFamily.cpp \
-    android/graphics/FontUtils.cpp \
-    android/graphics/CreateJavaOutputStreamAdaptor.cpp \
-    android/graphics/GIFMovie.cpp \
-    android/graphics/GraphicBuffer.cpp \
-    android/graphics/Graphics.cpp \
-    android/graphics/HarfBuzzNGFaceSkia.cpp \
-    android/graphics/Interpolator.cpp \
-    android/graphics/MaskFilter.cpp \
-    android/graphics/Matrix.cpp \
-    android/graphics/Movie.cpp \
-    android/graphics/MovieImpl.cpp \
-    android/graphics/NinePatch.cpp \
-    android/graphics/NinePatchPeeker.cpp \
-    android/graphics/Paint.cpp \
-    android/graphics/Path.cpp \
-    android/graphics/PathMeasure.cpp \
-    android/graphics/PathEffect.cpp \
-    android/graphics/Picture.cpp \
-    android/graphics/BitmapRegionDecoder.cpp \
-    android/graphics/Region.cpp \
-    android/graphics/Shader.cpp \
-    android/graphics/SurfaceTexture.cpp \
-    android/graphics/Typeface.cpp \
-    android/graphics/Utils.cpp \
-    android/graphics/YuvToJpegEncoder.cpp \
-    android/graphics/pdf/PdfDocument.cpp \
-    android/graphics/pdf/PdfEditor.cpp \
-    android/graphics/pdf/PdfRenderer.cpp \
-    android/graphics/pdf/PdfUtils.cpp \
-    android_media_AudioRecord.cpp \
-    android_media_AudioSystem.cpp \
-    android_media_AudioTrack.cpp \
-    android_media_DeviceCallback.cpp \
-    android_media_JetPlayer.cpp \
-    android_media_RemoteDisplay.cpp \
-    android_media_ToneGenerator.cpp \
-    android_hardware_Camera.cpp \
-    android_hardware_camera2_CameraMetadata.cpp \
-    android_hardware_camera2_legacy_LegacyCameraDevice.cpp \
-    android_hardware_camera2_legacy_PerfMeasurement.cpp \
-    android_hardware_camera2_DngCreator.cpp \
-    android_hardware_HardwareBuffer.cpp \
-    android_hardware_Radio.cpp \
-    android_hardware_SensorManager.cpp \
-    android_hardware_SerialPort.cpp \
-    android_hardware_SoundTrigger.cpp \
-    android_hardware_UsbDevice.cpp \
-    android_hardware_UsbDeviceConnection.cpp \
-    android_hardware_UsbRequest.cpp \
-    android_hardware_location_ActivityRecognitionHardware.cpp \
-    android_util_FileObserver.cpp \
-    android/opengl/poly_clip.cpp.arm \
-    android/opengl/util.cpp \
-    android_server_NetworkManagementSocketTagger.cpp \
-    android_server_Watchdog.cpp \
-    android_ddm_DdmHandleNativeHeap.cpp \
-    android_backup_BackupDataInput.cpp \
-    android_backup_BackupDataOutput.cpp \
-    android_backup_FileBackupHelperBase.cpp \
-    android_backup_BackupHelperDispatcher.cpp \
-    android_app_backup_FullBackup.cpp \
-    android_content_res_ObbScanner.cpp \
-    android_content_res_Configuration.cpp \
-    android_animation_PropertyValuesHolder.cpp \
-    com_android_internal_net_NetworkStatsFactory.cpp \
-    com_android_internal_os_FuseAppLoop.cpp \
-    com_android_internal_os_PathClassLoaderFactory.cpp \
-    com_android_internal_os_Zygote.cpp \
-    com_android_internal_util_VirtualRefBasePtr.cpp \
-    com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp \
-    hwbinder/EphemeralStorage.cpp \
-    fd_utils.cpp \
-
-LOCAL_C_INCLUDES += \
-    $(LOCAL_PATH)/include \
-    $(JNI_H_INCLUDE) \
-    $(LOCAL_PATH)/android/graphics \
-    $(LOCAL_PATH)/../../libs/hwui \
-    $(LOCAL_PATH)/../../../native/vulkan/include \
-    $(call include-path-for, bluedroid) \
-    $(call include-path-for, libhardware)/hardware \
-    $(call include-path-for, libhardware_legacy)/hardware_legacy \
-    $(TOP)/frameworks/base/media/jni \
-    $(TOP)/frameworks/rs/cpp \
-    $(TOP)/frameworks/rs \
-    $(TOP)/system/core/base/include \
-    $(TOP)/system/core/include \
-    $(TOP)/system/core/libappfuse/include \
-    $(TOP)/system/media/camera/include \
-    $(TOP)/system/media/private/camera/include \
-    $(TOP)/system/netd/include \
-    external/giflib \
-    external/pdfium/public \
-    external/skia/include/private \
-    external/skia/src/codec \
-    external/skia/src/core \
-    external/skia/src/effects \
-    external/skia/src/image \
-    external/skia/src/images \
-    external/sqlite/dist \
-    external/sqlite/android \
-    external/tremor/Tremor \
-    external/harfbuzz_ng/src \
-    libcore/include \
-    $(call include-path-for, audio-utils) \
-    frameworks/minikin/include \
-    external/freetype/include
-# TODO: clean up Minikin so it doesn't need the freetype include
-
-LOCAL_STATIC_LIBRARIES := \
-    libgif \
-    libseccomp_policy \
-    libselinux \
-    libcrypto \
-    libgrallocusage \
-
-LOCAL_SHARED_LIBRARIES := \
-    libmemtrack \
-    libandroidfw \
-    libappfuse \
-    libbase \
-    libnativehelper \
-    liblog \
-    libcutils \
-    libdebuggerd_client \
-    libutils \
-    libbinder \
-    libui \
-    libgui \
-    libsensor \
-    libinput \
-    libcamera_client \
-    libcamera_metadata \
-    libskia \
-    libsqlite \
-    libEGL \
-    libGLESv1_CM \
-    libGLESv2 \
-    libvulkan \
-    libziparchive \
-    libETC1 \
-    libhardware \
-    libhardware_legacy \
-    libselinux \
-    libicuuc \
-    libmedia \
-    libaudioclient \
-    libjpeg \
-    libusbhost \
-    libharfbuzz_ng \
-    libz \
-    libpdfium \
-    libimg_utils \
-    libnetd_client \
-    libradio \
-    libsoundtrigger \
-    libminikin \
-    libprocessgroup \
-    libnativebridge \
-    libradio_metadata \
-    libnativeloader \
-    libmemunreachable \
-    libhidlbase \
-    libhidltransport \
-    libhwbinder \
-    libvintf \
-    libnativewindow \
-
-LOCAL_SHARED_LIBRARIES += \
-    libhwui \
-    libdl \
-
-# our headers include libnativewindow's public headers
-LOCAL_EXPORT_SHARED_LIBRARY_HEADERS := \
-    libnativewindow \
-
-# we need to access the private Bionic header
-# <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
-LOCAL_C_INCLUDES += bionic/libc/private
-
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)/include
-
-# AndroidRuntime.h depends on nativehelper/jni.h
-LOCAL_EXPORT_C_INCLUDE_DIRS += libnativehelper/include
-
-LOCAL_MODULE:= libandroid_runtime
-
-# -Wno-unknown-pragmas: necessary for Clang as the GL bindings need to turn
-#                       off a GCC warning that Clang doesn't know.
-LOCAL_CFLAGS += -Wall -Werror -Wno-error=deprecated-declarations -Wunused -Wunreachable-code \
-        -Wno-unknown-pragmas
-
-# -Wno-c++11-extensions: Clang warns about Skia using the C++11 override keyword, but this project
-#                        is not being compiled with that level. Remove once this has changed.
-LOCAL_CLANG_CFLAGS += -Wno-c++11-extensions
-
-include $(BUILD_SHARED_LIBRARY)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index fc90fb3..9ad57b1 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -41,9 +41,6 @@
 
 namespace android {
 
-// Must be same with Java constant in Typeface.Builder. See Typeface.java
-constexpr jint RESOLVE_BY_FONT_TABLE = -1;
-
 struct NativeFamilyBuilder {
     NativeFamilyBuilder(uint32_t langId, int variant)
         : langId(langId), variant(variant), allowUnsupportedFont(false) {}
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index 86c97a1..eb2ca5d 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -30,14 +30,14 @@
 
 static jlong Typeface_createFromTypeface(JNIEnv* env, jobject, jlong familyHandle, jint style) {
     Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
-    Typeface* face = Typeface::createFromTypeface(family, (SkTypeface::Style)style);
+    Typeface* face = Typeface::createRelative(family, (SkTypeface::Style)style);
     // TODO: the following logic shouldn't be necessary, the above should always succeed.
     // Try to find the closest matching font, using the standard heuristic
     if (NULL == face) {
-        face = Typeface::createFromTypeface(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
+        face = Typeface::createRelative(family, (SkTypeface::Style)(style ^ SkTypeface::kItalic));
     }
     for (int i = 0; NULL == face && i < 4; i++) {
-        face = Typeface::createFromTypeface(family, (SkTypeface::Style)i);
+        face = Typeface::createRelative(family, (SkTypeface::Style)i);
     }
     return reinterpret_cast<jlong>(face);
 }
@@ -45,8 +45,7 @@
 static jlong Typeface_createFromTypefaceWithExactStyle(JNIEnv* env, jobject, jlong nativeInstance,
         jint weight, jboolean italic) {
     Typeface* baseTypeface = reinterpret_cast<Typeface*>(nativeInstance);
-    return reinterpret_cast<jlong>(
-            Typeface::createFromTypefaceWithStyle(baseTypeface, weight, italic));
+    return reinterpret_cast<jlong>(Typeface::createAbsolute(baseTypeface, weight, italic));
 }
 
 static jlong Typeface_createFromTypefaceWithVariation(JNIEnv* env, jobject, jlong familyHandle,
@@ -68,7 +67,7 @@
 
 static jlong Typeface_createWeightAlias(JNIEnv* env, jobject, jlong familyHandle, jint weight) {
     Typeface* family = reinterpret_cast<Typeface*>(familyHandle);
-    Typeface* face = Typeface::createWeightAlias(family, weight);
+    Typeface* face = Typeface::createWithDifferentBaseWeight(family, weight);
     return reinterpret_cast<jlong>(face);
 }
 
@@ -82,9 +81,9 @@
     return face->fSkiaStyle;
 }
 
-static jint Typeface_getBaseWeight(JNIEnv* env, jobject obj, jlong faceHandle) {
+static jint Typeface_getWeight(JNIEnv* env, jobject obj, jlong faceHandle) {
     Typeface* face = reinterpret_cast<Typeface*>(faceHandle);
-    return face->fBaseWeight;
+    return face->fStyle.getWeight() * 100;
 }
 
 static jlong Typeface_createFromArray(JNIEnv *env, jobject, jlongArray familyArray,
@@ -134,7 +133,7 @@
     { "nativeCreateWeightAlias",  "(JI)J", (void*)Typeface_createWeightAlias },
     { "nativeUnref",              "(J)V",  (void*)Typeface_unref },
     { "nativeGetStyle",           "(J)I",  (void*)Typeface_getStyle },
-    { "nativeGetBaseWeight",      "(J)I",  (void*)Typeface_getBaseWeight },
+    { "nativeGetWeight",      "(J)I",  (void*)Typeface_getWeight },
     { "nativeCreateFromArray",    "([JII)J",
                                            (void*)Typeface_createFromArray },
     { "nativeSetDefault",         "(J)V",   (void*)Typeface_setDefault },
diff --git a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
index b23757e..637234f 100644
--- a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
+++ b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
@@ -22,7 +22,7 @@
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/Log.h>
 
-// #include "activity_recognition.h"
+// #include <hardware/activity_recognition.h>
 // The activity recognition HAL is being deprecated. This means -
 //    i) Android framework code shall not depend on activity recognition
 //       being provided through the activity_recognition.h interface.
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 2cfaeeb..3e9ffce 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -28,7 +28,6 @@
 #include <utils/Log.h>
 #include <media/AudioSystem.h>
 #include <media/AudioTrack.h>
-#include <audio_utils/primitives.h>
 
 #include <binder/MemoryHeapBase.h>
 #include <binder/MemoryBase.h>
diff --git a/core/jni/android_os_VintfObject.cpp b/core/jni/android_os_VintfObject.cpp
index 9491a1e..fa9379e 100644
--- a/core/jni/android_os_VintfObject.cpp
+++ b/core/jni/android_os_VintfObject.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * 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.
@@ -16,41 +16,84 @@
 
 #define LOG_TAG "VintfObject"
 //#define LOG_NDEBUG 0
+#include <android-base/logging.h>
+
+#include <vector>
+#include <string>
 
 #include <JNIHelp.h>
 #include <vintf/VintfObject.h>
+#include <vintf/parse_string.h>
 #include <vintf/parse_xml.h>
 
 #include "core_jni_helpers.h"
 
+static jclass gString;
+static jclass gHashMapClazz;
+static jmethodID gHashMapInit;
+static jmethodID gHashMapPut;
+
 namespace android {
 
 using vintf::HalManifest;
-using vintf::RuntimeInfo;
+using vintf::SchemaType;
 using vintf::VintfObject;
+using vintf::XmlConverter;
+using vintf::Vndk;
 using vintf::gHalManifestConverter;
+using vintf::gCompatibilityMatrixConverter;
+using vintf::to_string;
 
-static jstring android_os_VintfObject_getDeviceManifest(JNIEnv* env, jclass clazz)
-{
-    const HalManifest *manifest = VintfObject::GetDeviceHalManifest();
-    if (manifest == nullptr) {
-        return nullptr;
+template<typename V>
+static inline jobjectArray toJavaStringArray(JNIEnv* env, const V& v) {
+    size_t i;
+    typename V::const_iterator it;
+    jobjectArray ret = env->NewObjectArray(v.size(), gString, NULL /* init element */);
+    for (i = 0, it = v.begin(); it != v.end(); ++i, ++it) {
+        env->SetObjectArrayElement(ret, i, env->NewStringUTF(it->c_str()));
     }
-    std::string xml = gHalManifestConverter(*manifest);
-    return env->NewStringUTF(xml.c_str());
+    return ret;
 }
 
-static jstring android_os_VintfObject_getFrameworkManifest(JNIEnv* env, jclass clazz)
-{
-    const HalManifest *manifest = VintfObject::GetFrameworkHalManifest();
-    if (manifest == nullptr) {
-        return nullptr;
+template<typename T>
+static void tryAddSchema(const T* object, const XmlConverter<T>& converter,
+        const std::string& description,
+        std::vector<std::string>* cStrings) {
+    if (object == nullptr) {
+        LOG(WARNING) << __FUNCTION__ << "Cannot get " << description;
+    } else {
+        cStrings->push_back(converter(*object));
     }
-    std::string xml = gHalManifestConverter(*manifest);
-    return env->NewStringUTF(xml.c_str());
 }
 
-static jint android_os_VintfObject_verify(JNIEnv *env, jclass clazz, jobjectArray packageInfo) {
+static void tryAddHalNamesAndVersions(const HalManifest *manifest,
+        const std::string& description,
+        std::set<std::string> *output) {
+    if (manifest == nullptr) {
+        LOG(WARNING) << __FUNCTION__ << "Cannot get " << description;
+    } else {
+        auto names = manifest->getHalNamesAndVersions();
+        output->insert(names.begin(), names.end());
+    }
+}
+
+static jobjectArray android_os_VintfObject_report(JNIEnv* env, jclass)
+{
+    std::vector<std::string> cStrings;
+
+    tryAddSchema(VintfObject::GetDeviceHalManifest(), gHalManifestConverter,
+            "device manifest", &cStrings);
+    tryAddSchema(VintfObject::GetFrameworkHalManifest(), gHalManifestConverter,
+            "framework manifest", &cStrings);
+    tryAddSchema(VintfObject::GetDeviceCompatibilityMatrix(), gCompatibilityMatrixConverter,
+            "device compatibility matrix", &cStrings);
+    tryAddSchema(VintfObject::GetFrameworkCompatibilityMatrix(), gCompatibilityMatrixConverter,
+            "framework compatibility matrix", &cStrings);
+
+    return toJavaStringArray(env, cStrings);
+}
+
+static jint android_os_VintfObject_verify(JNIEnv* env, jclass, jobjectArray packageInfo) {
     size_t count = env->GetArrayLength(packageInfo);
     std::vector<std::string> cPackageInfo{count};
     for (size_t i = 0; i < count; ++i) {
@@ -63,18 +106,61 @@
     return status;
 }
 
+static jobjectArray android_os_VintfObject_getHalNamesAndVersions(JNIEnv* env, jclass) {
+    std::set<std::string> halNames;
+    tryAddHalNamesAndVersions(VintfObject::GetDeviceHalManifest(),
+            "device manifest", &halNames);
+    tryAddHalNamesAndVersions(VintfObject::GetFrameworkHalManifest(),
+            "framework manifest", &halNames);
+    return toJavaStringArray(env, halNames);
+}
+
+static jstring android_os_VintfObject_getSepolicyVersion(JNIEnv* env, jclass) {
+    const HalManifest *manifest = VintfObject::GetDeviceHalManifest();
+    if (manifest == nullptr || manifest->type() != SchemaType::DEVICE) {
+        LOG(WARNING) << __FUNCTION__ << "Cannot get device manifest";
+        return nullptr;
+    }
+    std::string cString = to_string(manifest->sepolicyVersion());
+    return env->NewStringUTF(cString.c_str());
+}
+
+static jobject android_os_VintfObject_getVndkSnapshots(JNIEnv* env, jclass) {
+    const HalManifest *manifest = VintfObject::GetFrameworkHalManifest();
+    if (manifest == nullptr || manifest->type() != SchemaType::FRAMEWORK) {
+        LOG(WARNING) << __FUNCTION__ << "Cannot get framework manifest";
+        return nullptr;
+    }
+    jobject jMap = env->NewObject(gHashMapClazz, gHashMapInit);
+    for (const Vndk &vndk : manifest->vndks()) {
+        std::string key = to_string(vndk.versionRange());
+        env->CallObjectMethod(jMap, gHashMapPut,
+                env->NewStringUTF(key.c_str()), toJavaStringArray(env, vndk.libraries()));
+    }
+    return jMap;
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gVintfObjectMethods[] = {
-    {"getDeviceManifest",    "()Ljava/lang/String;",   (void*)android_os_VintfObject_getDeviceManifest},
-    {"getFrameworkManifest", "()Ljava/lang/String;",   (void*)android_os_VintfObject_getFrameworkManifest},
-    {"verify",               "([Ljava/lang/String;)I", (void*)android_os_VintfObject_verify},
+    {"report", "()[Ljava/lang/String;", (void*)android_os_VintfObject_report},
+    {"verify", "([Ljava/lang/String;)I", (void*)android_os_VintfObject_verify},
+    {"getHalNamesAndVersions", "()[Ljava/lang/String;", (void*)android_os_VintfObject_getHalNamesAndVersions},
+    {"getSepolicyVersion", "()Ljava/lang/String;", (void*)android_os_VintfObject_getSepolicyVersion},
+    {"getVndkSnapshots", "()Ljava/util/Map;", (void*)android_os_VintfObject_getVndkSnapshots},
 };
 
 const char* const kVintfObjectPathName = "android/os/VintfObject";
 
 int register_android_os_VintfObject(JNIEnv* env)
 {
+
+    gString = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/lang/String"));
+    gHashMapClazz = MakeGlobalRefOrDie(env, FindClassOrDie(env, "java/util/HashMap"));
+    gHashMapInit = GetMethodIDOrDie(env, gHashMapClazz, "<init>", "()V");
+    gHashMapPut = GetMethodIDOrDie(env, gHashMapClazz,
+            "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
     return RegisterMethodsOrDie(env, kVintfObjectPathName, gVintfObjectMethods,
             NELEM(gVintfObjectMethods));
 }
diff --git a/core/proto/android/providers/settings.proto b/core/proto/android/providers/settings.proto
index ce951de..ea40fd5 100644
--- a/core/proto/android/providers/settings.proto
+++ b/core/proto/android/providers/settings.proto
@@ -329,6 +329,8 @@
     SettingProto max_notification_enqueue_rate = 284;
     SettingProto cell_on = 285;
     SettingProto network_recommendations_package = 286;
+    SettingProto bluetooth_a2dp_supports_optional_codecs_prefix = 287;
+    SettingProto bluetooth_a2dp_optional_codecs_enabled_prefix = 288;
 }
 
 message SecureSettingsProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 5e34e05..5f6d820 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2209,6 +2209,22 @@
     <permission android:name="android.permission.UPDATE_CONFIG"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows a time zone rule updater application to request
+         the system installs / uninstalls timezone rules.
+         <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 -->
+    <permission android:name="android.permission.UPDATE_TIME_ZONE_RULES"
+        android:protectionLevel="signature|privileged" />
+
+    <!-- Must be required by a time zone rule updater application,
+         to ensure that only the system can trigger it.
+         @hide -->
+    <permission android:name="android.permission.TRIGGER_TIME_ZONE_RULES_CHECK"
+        android:protectionLevel="signature" />
+    <uses-permission android:name="android.permission.TRIGGER_TIME_ZONE_RULES_CHECK"/>
+
     <!-- Allows the system to reset throttling in shortcut manager.
          @hide -->
     <permission android:name="android.permission.RESET_SHORTCUT_MANAGER_THROTTLING"
@@ -2743,6 +2759,13 @@
     <permission android:name="android.permission.ACCESS_INPUT_FLINGER"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to disable/enable input devices.
+         Could be used to prevent unwanted touch events
+         on a touchscreen, for example during swimming or rain.
+         @hide -->
+    <permission android:name="android.permission.DISABLE_INPUT_DEVICE"
+        android:protectionLevel="signature" />
+
     <!-- Allows an application to configure and connect to Wifi displays
          @hide -->
     <permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
diff --git a/core/res/res/drawable/sym_def_app_icon.xml b/core/res/res/drawable/sym_def_app_icon.xml
index 0fdb0dd..9c02402 100644
--- a/core/res/res/drawable/sym_def_app_icon.xml
+++ b/core/res/res/drawable/sym_def_app_icon.xml
@@ -2,10 +2,7 @@
 <adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
     <background android:drawable="@android:color/white" />
     <foreground>
-        <inset android:insetLeft="27.7%"
-            android:insetTop="27.7%"
-            android:insetRight="27.7%"
-            android:insetBottom="27.7%">
+        <inset android:inset="27.7%">
             <bitmap android:src="@mipmap/sym_def_app_icon"/>
         </inset>
     </foreground>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 4524b6e..3477a7e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Opletberigte"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Kleinhandeldemonstrasie"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-verbinding"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Programme wat op die agtergrond loop"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> loop tans op die agtergrond"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> programme loop tans op die agtergrond"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tik vir besonderhede oor battery- en datagebruik"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veiligmodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-stelsel"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Skakel oor na persoonlik"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB vir MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Gekoppel aan \'n USB-toebehoorsel"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Tik vir meer opsies."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Oudiobykomstigheid word nie gesteun nie"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Tik vir meer inligting"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-ontfouter gekoppel"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tik om USB-ontfouting te deaktiveer."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Kies om USB-ontfouting te deaktiveer."</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index a3ebecb..6d2aa7a 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ማንቂያዎች"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"የችርቻሮ ማሳያ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"የዩኤስቢ ግንኙነት"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"በጀርባ ውስጥ የሚያሄዱ መተግበሪያዎች"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> በጀርባ ውስጥ እያሄደ ነው"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> መተግበሪያዎች በጀርባ ውስጥ እያሄዱ ነው"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"በባትሪ እና ውሂብ አጠቃቀም ላይ ዝርዝሮችን ለማግኘት መታ ያድርጉ"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>፣ <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"የሚያስተማምን ሁነታ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android ስርዓት"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"ወደ የግል ቀይር"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"ዩኤስቢ ለMIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"ለUSB ተቀጥላ ተያይዟል"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"ለተጨማሪ አማራጮች መታ ያድርጉ።"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB አድስ ተያይዟል"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"የዩኤስቢ ማረሚያን ለማሰናከል መታ ያድርጉ።"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB ማረሚያ ላለማንቃት ምረጥ።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index d1b9dcb..a080138 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -76,7 +76,7 @@
     <string name="ClirMmi" msgid="7784673673446833091">"معرف المتصل الصادر"</string>
     <string name="ColpMmi" msgid="3065121483740183974">"معرّف الخط المتصل"</string>
     <string name="ColrMmi" msgid="4996540314421889589">"تقييد معرّف الخط المتصل"</string>
-    <string name="CfMmi" msgid="5123218989141573515">"اعادة توجيه المكالمة"</string>
+    <string name="CfMmi" msgid="5123218989141573515">"إعادة توجيه المكالمة"</string>
     <string name="CwMmi" msgid="9129678056795016867">"انتظار المكالمة"</string>
     <string name="BaMmi" msgid="455193067926770581">"حظر الاتصال"</string>
     <string name="PwdMmi" msgid="7043715687905254199">"تغيير كلمة المرور"</string>
@@ -92,7 +92,7 @@
     <string name="CLIRDefaultOffNextCallOn" msgid="6179425182856418465">"الإعداد الافتراضي لمعرف المتصل هو غير مقيّد. الاتصال التالي: مقيّد"</string>
     <string name="CLIRDefaultOffNextCallOff" msgid="2567998633124408552">"الإعداد الافتراضي لمعرف المتصل هو غير مقيّد. الاتصال التالي: غير مقيّد"</string>
     <string name="serviceNotProvisioned" msgid="8614830180508686666">"الخدمة غير متوفرة."</string>
-    <string name="CLIRPermanent" msgid="3377371145926835671">"لا يمكنك تغيير إعداد معرف المتصل."</string>
+    <string name="CLIRPermanent" msgid="3377371145926835671">"لا يمكنك تغيير إعداد معرّف المتصل."</string>
     <string name="RestrictedOnDataTitle" msgid="1322504692764166532">"ليست هناك خدمة بيانات"</string>
     <string name="RestrictedOnEmergencyTitle" msgid="1236071219598685236">"لا تتوفر خدمة طوارئ"</string>
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"لا تتوفر خدمة صوتية"</string>
@@ -104,7 +104,7 @@
     <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"يتعذر الوصول إلى الشبكة"</string>
     <string name="NetworkPreferenceSwitchSummary" msgid="4164230263214915351">"‏لتحسين الاستقبال، يمكنك تجربة تغيير النوع المحدّد في النظام &gt; الشبكة والإنترنت &gt; شبكات الجوّال &gt; نوع الشبكة المفضّل."</string>
     <string name="notification_channel_network_alert" msgid="4427736684338074967">"التنبيهات"</string>
-    <string name="notification_channel_call_forward" msgid="2419697808481833249">"اعادة توجيه المكالمة"</string>
+    <string name="notification_channel_call_forward" msgid="2419697808481833249">"إعادة توجيه المكالمة"</string>
     <string name="notification_channel_emergency_callback" msgid="6686166232265733921">"وضع معاودة الاتصال بالطوارئ"</string>
     <string name="notification_channel_mobile_data_alert" msgid="6130875231721406231">"تنبيهات بيانات الجوّال"</string>
     <string name="notification_channel_sms" msgid="3441746047346135073">"‏الرسائل القصيرة SMS"</string>
@@ -277,16 +277,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"التنبيهات"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"عرض توضيحي لبائع التجزئة"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"‏اتصال USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"التطبيقات التي تعمل في الخلفية"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"جارٍ تشغيل <xliff:g id="APP_NAME">%1$s</xliff:g> في الخلفية"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"جارٍ تشغيل <xliff:g id="NUMBER">%1$d</xliff:g> تطبيق في الخلفية"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"انقر للحصول على تفاصيل حول البطارية واستخدام البيانات"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>، <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"الوضع الآمن"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏نظام Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"التبديل إلى الشخصي"</string>
@@ -1263,6 +1258,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏USB لـ MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"‏الاتصال بجهاز USB ملحق"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"انقر للحصول على المزيد من الخيارات."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"ملحق الصوت غير متوافق"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"انقر للحصول على مزيد من المعلومات"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏تم توصيل تصحيح أخطاء USB"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"‏انقر لتعطيل تصحيح أخطاء USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏اختيار تعطيل تصحيح أخطاء USB."</string>
@@ -1380,7 +1377,7 @@
     <string name="tethered_notification_message" msgid="2113628520792055377">"انقر للإعداد."</string>
     <string name="back_button_label" msgid="2300470004503343439">"رجوع"</string>
     <string name="next_button_label" msgid="1080555104677992408">"التالي"</string>
-    <string name="skip_button_label" msgid="1275362299471631819">"تخطٍ"</string>
+    <string name="skip_button_label" msgid="1275362299471631819">"تخطي"</string>
     <string name="no_matches" msgid="8129421908915840737">"ليس هناك أية مطابقات"</string>
     <string name="find_on_page" msgid="1946799233822820384">"بحث في الصفحة"</string>
     <plurals name="matches_found" formatted="false" msgid="1210884353962081884">
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 552c4e3..72d0bdc 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Siqnallar"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Pərakəndə demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB əlaqə"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Arxa fonda işləyən tətbiqlər"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> arxa fonda işləyir"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> tətbiq arxa fonda işləyir"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Batareya və data istifadəsi haqqında ətraflı məlumat üçün klikləyin"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Təhlükəsiz rejim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistemi"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Şəxsi profilə keçirin"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI üçün USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB aksesuara qoşuldu"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Əlavə seçimlər üçün tıklayın."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Audio aksesuar dəstəklənmir"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Daha çox məlumat üçün klikləyin"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB sazlama qoşuludur"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB debaqı deaktivasiya etmək üçün tıklayın."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USb debaqı deaktivasiya etməyi seçin."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 9fc3a28c..6667a414 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -268,16 +268,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Obaveštenja"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Režim demonstracije za maloprodajne objekte"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB veza"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplikacije pokrenute u pozadini"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta u pozadini"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Aplikacije (<xliff:g id="NUMBER">%1$d</xliff:g>) su pokrenute u pozadini"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Dodirnite da biste pregledali detalje o bateriji i potrošnji podataka"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Bezbedni režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Pređi na Lični profil"</string>
@@ -300,13 +295,13 @@
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"upućuje telefonske pozive i upravlja njima"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Senzori za telo"</string>
     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"pristupa podacima senzora o vitalnim funkcijama"</string>
-    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Preuzima sadržaj prozora"</string>
+    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"da preuzima sadržaj prozora"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Proverava sadržaj prozora sa kojim ostvarujete interakciju."</string>
-    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Uključi Istraživanja dodirom"</string>
+    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"da uključi Istraživanja dodirom"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Stavke koje dodirnete će biti izgovorene naglas, a možete da se krećete po ekranu pokretima."</string>
-    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Prati tekst koji unosite"</string>
+    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"da prati tekst koji unosite"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Obuhvata lične podatke kao što su brojevi kreditnih kartica i lozinke."</string>
-    <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Upravljaj uvećanjem prikaza"</string>
+    <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"da upravlja uvećanjem prikaza"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Upravlja nivoom zumiranja prikaza i određivanjem položaja."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Obavljanje pokreta"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Može da dodiruje, lista, skuplja prikaz i obavlja druge pokrete."</string>
@@ -1053,7 +1048,7 @@
     <string name="noApplications" msgid="2991814273936504689">"Nijedna aplikacija ne može da obavlja ovu radnju."</string>
     <string name="aerr_application" msgid="250320989337856518">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> je zaustavljena"</string>
     <string name="aerr_process" msgid="6201597323218674729">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> je zaustavljen"</string>
-    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> se stalno zaustavlja"</string>
+    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> se stalno zaustavlja(ju)"</string>
     <string name="aerr_process_repeated" msgid="6235302956890402259">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> se stalno zaustavlja"</string>
     <string name="aerr_restart" msgid="7581308074153624475">"Ponovo otvori aplikaciju"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Pošaljite povratne informacije"</string>
@@ -1203,6 +1198,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Povezano sa USB dodatkom"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za još opcija."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Dodatna oprema za audio sadržaj nije podržana"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Dodirnite za više informacija"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka sa USB-a je uspostavljeno"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da biste onemogućili otklanjanje grešaka sa USB-a."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Izaberite da biste onemogućili otklanjanja grešaka sa USB-a."</string>
@@ -1312,7 +1309,7 @@
     <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite da biste podesili"</string>
     <string name="upload_file" msgid="2897957172366730416">"Odaberi datoteku"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabrana nijedna datoteka"</string>
-    <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
+    <string name="reset" msgid="2448168080964209908">"Resetuj"</string>
     <string name="submit" msgid="1602335572089911941">"Pošalji"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Režim rada u automobilu je omogućen"</string>
     <string name="car_mode_disable_notification_message" msgid="6301524980144350051">"Dodirnite da biste izašli iz režima rada u automobilu."</string>
@@ -1346,7 +1343,7 @@
     <string name="sync_really_delete" msgid="2572600103122596243">"Izbriši stavke"</string>
     <string name="sync_undo_deletes" msgid="2941317360600338602">"Opozovi brisanja"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"Ne radi ništa za sada"</string>
-    <string name="choose_account_label" msgid="5655203089746423927">"Izbor naloga"</string>
+    <string name="choose_account_label" msgid="5655203089746423927">"Izaberite nalog"</string>
     <string name="add_account_label" msgid="2935267344849993553">"Dodaj nalog"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"Dodaj nalog"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"Povećavanje"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index fdd15d3..c564168 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -271,16 +271,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Абвесткi"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Дэманстрацыйны рэжым для пунктаў продажу"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Падключэнне USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Праграмы, якія працуюць у фонавым рэжыме"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> працуе ў фонавым рэжыме"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Праграмы (<xliff:g id="NUMBER">%1$d</xliff:g>) працуюць у фонавым рэжыме"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Дакраніцеся, каб атрымаць падрабязныя звесткі пра выкарыстанне трафіка і акумулятара"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Бяспечны рэжым"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Сістэма Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Пераключыцца на асабісты"</string>
@@ -1223,6 +1218,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB для MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Падключаны да USB-прылады"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Дакраніцеся, каб атрымаць іншыя параметры."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Аксесуар аўдыя не падтрымліваецца"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Націсніце, каб атрымаць дадатковую інфармацыю"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Адладка па USB падключана"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Дакраніцеся, каб адключыць адладку па USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Выберыце, каб адключыць адладку USB."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index b03e09e..8c78183 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Сигнали"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Демонстрационен режим за магазини"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB връзка"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Приложения, работещи на заден план"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> работи на заден план"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> приложения работят на заден план"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Докоснете за подробности относно използването на батерията и преноса на данни"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безопасен режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Превключване към личния потребителски профил"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB за MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Установена е връзка с аксесоар за USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Докоснете за още опции."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отстраняване на грешки през USB"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Докоснете, за да деактивирате отстраняването на грешки през USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Изберете, за да деактивирате отстраняването на грешки през USB."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index b574890..4eaa927 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"সতর্কতাগুলি"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"খুচরা বিক্রয়ের ডেমো"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB সংযোগ"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"পটভূমিতে অ্যাপ চালু আছে"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"পটভূমিতে <xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপ চালু আছে"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"পটভূমিতে <xliff:g id="NUMBER">%1$d</xliff:g>টি অ্যাপ চালু আছে"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"ব্যাটারি এবং ডেটার ব্যবহারের বিশদ বিবরণের জন্য ট্যাপ করুন"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"নিরাপদ মোড"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android সিস্টেম"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"ব্যক্তিগততে পাল্টান"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI এর জন্য USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"একটি USB যন্ত্রাংশতে সংযুক্ত হয়েছে"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"আরো বিকল্পের জন্য আলতো চাপুন৷"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ডিবাগিং সংযুক্ত হয়েছে"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ডিবাগিং অক্ষম করতে আলতো চাপুন৷"</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 37fa55f..e811f71 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -268,16 +268,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozorenja"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Promotivna demonstracija u maloprodaji"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB veza"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplikacije koje rade u pozadini"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> radi u pozadini"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Broj aplikacija koje rade u pozadini: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Dodirnite za detalje o bateriji i prijenosu podataka"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistem"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Prebacite se na lični"</string>
@@ -1207,6 +1202,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Uspostavljena veza sa USB pohranom"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za više opcija."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Audio pribor nije podržan"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Dodirnite za više informacija"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Otklanjanje grešaka putem uređaja spojenog na USB je uspostavljeno"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da onemogućite otklanjanje grešaka putem uređaja spojenog na USB."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
@@ -1317,7 +1314,7 @@
     <string name="vpn_lockdown_config" msgid="5099330695245008680">"Dodirnite za postavke"</string>
     <string name="upload_file" msgid="2897957172366730416">"Odabir fajla"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nije izabran nijedan fajl"</string>
-    <string name="reset" msgid="2448168080964209908">"Vrati na zadano"</string>
+    <string name="reset" msgid="2448168080964209908">"Vraćanje na zadano"</string>
     <string name="submit" msgid="1602335572089911941">"Potvrdi"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Način rada u autu omogućen"</string>
     <string name="car_mode_disable_notification_message" msgid="6301524980144350051">"Dodirnite za izlaz iz načina rada u automobilu"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 0b77c82..a3e9fc9 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demostració comercial"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Connexió USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplicacions que s\'estan executant en segon pla"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> s\'està executant en segon pla"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicacions s\'estan executant en segon pla"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Toca per obtenir informació sobre l\'ús de dades i la bateria"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode segur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Canvia al perfil personal"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB per a MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connectat a un accessori USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Toca per veure més opcions."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuració USB activada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toca per desactivar la depuració USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecciona per desactivar la depuració USB"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 31f0826..e02eaec 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -271,16 +271,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozornění"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Prodejní ukázka"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Připojení USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplikace běžící na pozadí"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> běží na pozadí"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Aplikace (<xliff:g id="NUMBER">%1$d</xliff:g>) běží na pozadí"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Klepnutím zobrazíte podrobnosti o využití baterie a dat"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Nouzový režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Přepnout na osobní profil"</string>
@@ -1223,6 +1218,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB v režimu MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Připojeno k perifernímu zařízení USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Klepnutím zobrazíte další možnosti."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Zvukové příslušenství není podporováno"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Klepnutím zobrazíte další informace"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladění přes USB připojeno"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Klepnutím zakážete ladění USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Vyberte, chcete-li zakázat ladění USB."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index a258f08..b1df60b 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Underretninger"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo til udstilling i butik"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-forbindelse"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apps, der kører i baggrunden"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> kører i baggrunden"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> apps kører i baggrunden"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tryk for at se oplysninger om batteri- og dataforbrug"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikker tilstand"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Skift til Tilpasset"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB til MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Tilsluttet et USB-ekstraudstyr"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Tryk for at se flere muligheder."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-fejlretning er tilsluttet"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tryk for at deaktivere fejlretning via USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Vælg for at deaktivere USB-fejlretning."</string>
@@ -1618,7 +1617,7 @@
     <string name="package_installed_device_owner" msgid="6875717669960212648">"Installeret af din administrator"</string>
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Opdateret af din administrator"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Slettet af din administrator"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"Batterisparefunktionen hjælper med at forlænge batteriets levetid ved at reducere enhedens ydeevne og begrænse vibration, placeringstjenester og det meste baggrundsdata. E-mail, beskedfunktioner og andre apps, der benytter synkronisering, opdateres muligvis ikke, medmindre du åbner dem.\n\nBatterisparefunktionen slukker automatisk, når enheden oplader."</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"Batterisparefunktionen hjælper med at forlænge batteriets levetid ved at reducere enhedens ydeevne og begrænse vibration, placeringstjenester og det meste baggrundsdata. E-mail, beskedfunktioner og andre apps, der benytter synkronisering, opdateres muligvis ikke, medmindre du åbner dem.\n\nBatterisparefunktionen deaktiveres automatisk, når enheden oplader."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Datasparefunktionen forhindrer nogle apps i at sende eller modtage data i baggrunden for at reducere dataforbruget. En app, der er i brug, kan få adgang til data, men gør det måske ikke så ofte. Dette kan f.eks. betyde, at billeder ikke vises, før du trykker på dem."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Vil du slå Datasparefunktion til?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Slå til"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 5a70d9b..d7810a2 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Warnmeldungen"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo für Einzelhandel"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-Verbindung"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apps, die im Hintergrund ausgeführt werden"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> wird im Hintergrund ausgeführt"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> Apps werden im Hintergrund ausgeführt"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Für weitere Informationen zur Akku- und Datennutzung tippen"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Zu \"Privat\" wechseln"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB für MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Mit USB-Zubehör verbunden"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Für weitere Optionen tippen."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging aktiviert"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Zum Deaktivieren von USB-Debugging tippen."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB-Debugging deaktivieren: auswählen"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 0cc6dc6..cda02d2 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ειδοποιήσεις"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Επίδειξη λιανικής"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Σύνδεση USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Εφαρμογές που εκτελούνται στο παρασκήνιο"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εκτελείται στο παρασκήνιο"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> εφαρμογές εκτελούνται στο παρασκήνιο"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Πατήστε για λεπτομέρειες σχετικά με τη χρήση μπαταρίας και δεδομένων"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Ασφαλής λειτουργία"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Σύστημα Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Μετάβαση σε προσωπικό προφίλ"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB για MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Σύνδεση σε αξεσουάρ USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Πατήστε για περισσότερες επιλογές."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Το εξάρτημα ήχου δεν υποστηρίζεται"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Πατήστε για να δείτε περισσότερες πληροφορίες"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Πατήστε για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 4976b03..d1d474b 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Retail demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB connection"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apps running in background"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> is running in the background"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> apps are running in the background"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tap for details on battery and data usage"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connected to a USB accessory"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Tap for more options."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Audio accessory not supported"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Tap for more info"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tap to disable USB debugging."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 4976b03..d1d474b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Retail demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB connection"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apps running in background"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> is running in the background"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> apps are running in the background"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tap for details on battery and data usage"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connected to a USB accessory"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Tap for more options."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Audio accessory not supported"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Tap for more info"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tap to disable USB debugging."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 4976b03..d1d474b 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerts"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Retail demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB connection"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apps running in background"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> is running in the background"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> apps are running in the background"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tap for details on battery and data usage"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android system"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Switch to Personal"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connected to a USB accessory"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Tap for more options."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Audio accessory not supported"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Tap for more info"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB debugging connected"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tap to disable USB debugging."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Select to disable USB debugging."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 5515ae1..d95cdb6 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo para punto de venta"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Conexión USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apps que se ejecutan en segundo plano"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando en segundo plano"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> apps se están ejecutando en segundo plano"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Presiona para obtener información sobre el uso de datos y de la batería"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Cambiar al perfil personal"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Presiona para ver más opciones."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"El accesorio de audio no es compatible"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Presiona para obtener más información"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración por USB conectada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Presiona para inhabilitar la depuración por USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccionar para desactivar la depuración por USB"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 33c0e5c..a986c21 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo para tiendas"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Conexión USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplicaciones que se están ejecutando en segundo plano"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> se está ejecutando en segundo plano"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicaciones se están ejecutando en segundo plano"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Toca para ver información detallada sobre el uso de datos y la batería"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Cambiar a perfil personal"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Toca para ver más opciones."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Accesorio de audio no compatible"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Toca para obtener más información"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB habilitada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toca para inhabilitar la depuración USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccionar para inhabilitar la depuración USB"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 1c76b3f..c426454 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Teatised"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Poedemo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-ühendus"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Rakendusi käitatakse taustal"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Rakendust <xliff:g id="APP_NAME">%1$s</xliff:g> käitatakse taustal"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> rakendust käitatakse taustal"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Aku ja andmekasutuse üksikasjade nägemiseks puudutage"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Turvarežiim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-süsteem"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Lülita isiklikule profiilile"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI jaoks"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ühendatud USB-lisaseadmega"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Puudutage lisavalikute nägemiseks."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-silumine ühendatud"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Puudutage USB-silumise keelamiseks."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Valige USB silumise keelamiseks"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 78aed23..c4585de 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Abisuak"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Saltzaileentzako demoa"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB konexioa"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplikazioak exekutatzen ari dira atzeko planoan"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> exekutatzen ari da atzeko planoan"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> exekutatzen ari dira atzeko planoan"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Sakatu bateriaren eta datuen erabilerari buruzko xehetasunak ikusteko"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modu segurua"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistema"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Aldatu profil pertsonalera"</string>
@@ -304,7 +299,7 @@
     <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Behatu idazten duzun testua"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Ez da salbuespenik egiten datu pertsonalekin, hala nola, kreditu-txartelen zenbakiekin eta pasahitzekin."</string>
     <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Kontrolatu pantailaren zoom-maila"</string>
-    <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolatu pantailaren zoom-maila eta kokapena."</string>
+    <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Kontrolatu pantailaren zoom-maila eta posizioa."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Keinuak egin"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Sakatu, lerratu, atximurkatu eta beste hainbat keinu egin ditzake."</string>
     <string name="capability_title_canCaptureFingerprintGestures" msgid="6309568287512278670">"Hatz-marken keinuak"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI modurako USBa"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB osagarri batera konektatuta"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Sakatu aukera gehiago ikusteko."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Ez da onartzen audio-osagarri hori"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Informazio gehiago lortzeko, sakatu hau"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB arazketa konektatuta"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Sakatu USB arazketa desgaitzeko."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index cd8e750..b12951a 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"هشدارها"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"نمونه برای خرده‌فروشان"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"‏اتصال USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"برنامه‌هایی که در پس‌زمینه اجرا می‌شوند"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> در پس‌زمینه درحال اجرا شدن است"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> برنامه در پس‌زمینه درحال اجرا شدن هستند"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"برای جزئیات مربوط به مصرف باتری و داده، ضربه بزنید"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>، <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"حالت ایمن"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏سیستم Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"رفتن به نمایه شخصی"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏USB برای MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"‏به یک وسیله جانبی USB وصل شده است"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"برای گزینه‌های بیشتر ضربه بزنید."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏اشکال‌زدایی USB متصل شد"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"‏برای غیرفعال کردن اشکال‌زدایی USB ضربه بزنید."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏انتخاب کنید تا رفع عیب USB غیرفعال شود."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 5690669..4d1b075 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ilmoitukset"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Esittelytila"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-yhteys"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Sovelluksia käynnissä taustalla"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> on käynnissä taustalla."</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> sovellusta on käynnissä taustalla."</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Katso lisätietoja akun ja datan käytöstä napauttamalla."</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Suojattu tila"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-järjestelmä"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Siirry henkilökohtaiseen profiiliin"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB on MIDI-tilassa"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Liitetty USB-laitteeseen"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Näet lisää vaihtoehtoja napauttamalla."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Äänilisälaitetta ei tueta."</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Saat lisätietoja napauttamalla."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-vianetsintä yhdistetty"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Poista USB-vianetsintä käytöstä napauttamalla."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Poista USB-vianetsintä käytöstä valitsemalla tämä."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 7797274..b067fb9 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Démo en magasin"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Connexion USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Applications qui fonctionnent en arrière-plan"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> fonctionne en arrière-plan"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> applications fonctionnent en arrière-plan"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Touchez ici pour afficher des détails sur l\'usage de la pile et des données"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Passer au profil personnel"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB pour MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connecté à un accessoire USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Touchez pour afficher plus d\'options."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB connecté"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Touchez pour désactiver le débogage USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Sélectionnez cette option pour désactiver le débogage USB."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 761947e..ba33460 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertes"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Démonstration en magasin"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Connexion USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Applications en cours d\'exécution en arrière-plan"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> s\'exécute en arrière-plan"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> applications s\'exécutent en arrière-plan"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Appuyer pour obtenir des informations sur l\'utilisation de la batterie et des données"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode sécurisé"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Système Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Passer au profil personnel"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB en mode MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Connecté à un accessoire USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Appuyez ici pour plus d\'options."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Débogage USB activé"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Appuyez ici pour désactiver le débogage USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Sélectionnez cette option pour désactiver le débogage USB."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 2c58acb..0a5ba2c 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demostración comercial"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"conexión USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplicacións que se executan en segundo plano"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Estase executando en segundo plano a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Estanse executando en segundo plano <xliff:g id="NUMBER">%1$d</xliff:g> aplicacións"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Toca para obter información sobre a batería e o uso de datos"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Cambiar ao perfil persoal"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a un accesorio USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Toca para ver máis opcións."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuración USB conectada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toca para desactivar a depuración de erros de USB."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 77f7212..54c493d 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ચેતવણીઓ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"રિટેલ ડેમો"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB કનેક્શન"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"પૃષ્ઠભૂમિમાં ચાલી રહેલ ઍપ્લિકેશનો"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> પૃષ્ઠભૂમિમાં ચાલી રહી છે"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> ઍપ્લિકેશન પૃષ્ઠભૂમિમાં ચાલી રહી છે"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"બૅટરી અને ડેટા વપરાશ વિશેની વિગતો માટે ટૅપ કરો"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"સુરક્ષિત મોડ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android સિસ્ટમ"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"વ્યક્તિગત પર સ્વિચ કરો"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI માટે USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB ઍક્સેસરીથી કનેક્ટ થયાં"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"વધુ વિકલ્પો માટે ટૅપ કરો."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ડીબગિંગ કનેક્ટ થયું."</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ડીબગિંગ અક્ષમ કરવા માટે ટૅપ કરો."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 0a672ca..74a7a04 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"सूचनाएं"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"खुदरा डेमो"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB कनेक्शन"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"ऐप्लिकेशन बैकग्राउंड में चल रहे हैं"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> बैकग्राउंड में चल रहा है"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> ऐप्लिकेशन बैकग्राउंड में चल रहे हैं"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"बैटरी और डेटा उपयोग के विवरण पाने के लिए टैप करें"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android सिस्‍टम"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"व्यक्तिगत प्रोफ़ाइल में स्विच करें"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI के लिए USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB सहायक सामग्री से कनेक्‍ट कि‍या गया"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"अधिक विकल्पों के लिए टैप करें."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"ऑडियो एक्सेसरी इस पर काम नहीं करती है"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"अधिक जानकारी के लिए टैप करें"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग कनेक्ट किया गया"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB डीबग करना अक्षम करने के लिए टैप करें."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डीबग करना अक्षम करने के लिए चुनें."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 48f4cf7..3a11fe7 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -268,16 +268,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozorenja"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Prodajni demo-način"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB veza"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Izvođenje aplikacija u pozadini"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> izvodi se u pozadini"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Aplikacije koje se izvode u pozadini: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Dodirnite da biste vidjeli pojedinosti o potrošnji baterije i podataka"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Siguran način rada"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sustav Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Prijeđite na osobni"</string>
@@ -1203,6 +1198,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Spojen na USB pribor"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Dodirnite za više opcija."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Audiododatak nije podržan"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Dodirnite za više informacija"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Priključen je alat za otklanjanje pogrešaka USB-om"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Dodirnite da biste onemogućili otklanjanje pogrešaka putem USB-a."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Odaberite da biste onemogućili rješavanje programske pogreške na USB-u."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 8af3ff5..6da0f11 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Értesítések"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Kiskereskedelmi bemutató"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-kapcsolat"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"A háttérben még futnak alkalmazások"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás még fut a háttérben"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> alkalmazás még fut a háttérben"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Az akkumulátor töltöttségének és az adathasználat részleteinek megtekintéséhez koppintson"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Biztonsági üzemmód"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android rendszer"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Átváltás személyes profilra"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI-hez"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Csatlakoztatva egy USB-kiegészítőhöz"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Koppintson a további beállítások megjelenítéséhez."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Ez az audiotartozék nem támogatott"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Koppintson, ha további információra van szüksége"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB hibakereső csatlakoztatva"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Koppintson az USB fejlesztő mód kikapcsolásához."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Válassza ezt az USB hibakeresés kikapcsolásához."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 2ca708d..e2523a6 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ծանուցումներ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Խանութի ցուցադրական ռեժիմ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB կապակցում"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Հետին ֆոնին գործարկվող հավելվածներ"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը գործարկվում է հետին ֆոնին"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> հավելվածները գործարկվում են հետին ֆոնին"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Հպել՝ մարտկոցի և տվյալների օգտագործման մասին մանրամասներ ստանալու համար"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Անվտանգ ռեժիմ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android համակարգ"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Անցնել անհատական պրոֆիլին"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-ի USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Կապակցված է USB լրասարքի"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Հպեք՝ լրացուցիչ ընտրանքների համար:"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB վրիպազերծումը միացված է"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Հպեք՝ USB վրիպազերծումն անջատելու համար:"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Ընտրել` USB կարգաբերումը կասեցնելու համար:"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index aa325ac..f50a384 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -231,12 +231,12 @@
     <string name="bugreport_title" msgid="2667494803742548533">"Ambil laporan bug"</string>
     <string name="bugreport_message" msgid="398447048750350456">"Ini akan mengumpulkan informasi status perangkat Anda saat ini, untuk dikirimkan sebagai pesan email. Harap bersabar, mungkin perlu waktu untuk memulai laporan bug hingga siap dikirim."</string>
     <string name="bugreport_option_interactive_title" msgid="8635056131768862479">"Laporan interaktif"</string>
-    <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"Gunakan ini di berbagai keadaan. Ini memungkinkan Anda melacak kemajuan laporan, memasukkan detail masalah selengkapnya, dan mengambil tangkapan layar. Mungkin menghilangkan beberapa bagian yang jarang digunakan dan yang perlu waktu lama untuk dilaporkan."</string>
+    <string name="bugreport_option_interactive_summary" msgid="229299488536107968">"Gunakan ini di berbagai keadaan. Ini memungkinkan Anda melacak kemajuan laporan, memasukkan detail masalah selengkapnya, dan mengambil screenshot. Mungkin menghilangkan beberapa bagian yang jarang digunakan dan yang perlu waktu lama untuk dilaporkan."</string>
     <string name="bugreport_option_full_title" msgid="6354382025840076439">"Laporan lengkap"</string>
-    <string name="bugreport_option_full_summary" msgid="7210859858969115745">"Gunakan opsi ini untuk meminimalkan gangguan sistem jika perangkat tidak responsif atau terlalu lambat, atau jika Anda perlu semua bagian laporan. Tidak mengizinkan Anda memasukkan lebih banyak detail atau mengambil tangkapan layar tambahan."</string>
+    <string name="bugreport_option_full_summary" msgid="7210859858969115745">"Gunakan opsi ini untuk meminimalkan gangguan sistem jika perangkat tidak responsif atau terlalu lambat, atau jika Anda perlu semua bagian laporan. Tidak mengizinkan Anda memasukkan lebih banyak detail atau mengambil screenshot tambahan."</string>
     <plurals name="bugreport_countdown" formatted="false" msgid="6878900193900090368">
-      <item quantity="other">Mengambil tangkapan layar untuk laporan bug dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik.</item>
-      <item quantity="one">Mengambil tangkapan layar untuk laporan bug dalam <xliff:g id="NUMBER_0">%d</xliff:g> detik.</item>
+      <item quantity="other">Mengambil screenshot untuk laporan bug dalam <xliff:g id="NUMBER_1">%d</xliff:g> detik.</item>
+      <item quantity="one">Mengambil screenshot untuk laporan bug dalam <xliff:g id="NUMBER_0">%d</xliff:g> detik.</item>
     </plurals>
     <string name="global_action_toggle_silent_mode" msgid="8219525344246810925">"Mode senyap"</string>
     <string name="global_action_silent_mode_on_status" msgid="3289841937003758806">"Suara MATI"</string>
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Notifikasi"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo promo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Sambungan USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplikasi yang sedang berjalan di latar belakang"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan di latar belakang"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> aplikasi sedang berjalan di latar belakang"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tap untuk melihat detail baterai dan penggunaan data"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mode aman"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Beralih ke Pribadi"</string>
@@ -820,7 +815,7 @@
     <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nYakin ingin beranjak dari laman ini?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Konfirmasi"</string>
     <string name="double_tap_toast" msgid="4595046515400268881">"Kiat: Ketuk dua kali untuk memperbesar dan memperkecil."</string>
-    <string name="autofill_this_form" msgid="4616758841157816676">"Isiotomatis"</string>
+    <string name="autofill_this_form" msgid="4616758841157816676">"IsiOtomatis"</string>
     <string name="setup_autofill" msgid="7103495070180590814">"Siapkan Pengisian Otomatis"</string>
     <string name="autofill_address_name_separator" msgid="6350145154779706772">"  "</string>
     <string name="autofill_address_summary_name_format" msgid="3268041054899214945">"$1$2$3"</string>
@@ -981,7 +976,7 @@
     <string name="selectTextMode" msgid="1018691815143165326">"Pilih teks"</string>
     <string name="undo" msgid="7905788502491742328">"Urungkan"</string>
     <string name="redo" msgid="7759464876566803888">"Ulangi"</string>
-    <string name="autofill" msgid="3035779615680565188">"Isiotomatis"</string>
+    <string name="autofill" msgid="3035779615680565188">"IsiOtomatis"</string>
     <string name="textSelectionCABTitle" msgid="5236850394370820357">"Pemilihan teks"</string>
     <string name="addToDictionary" msgid="4352161534510057874">"Tambahkan ke kamus"</string>
     <string name="deleteText" msgid="6979668428458199034">"Hapus"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB untuk MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Tersambung ke aksesori USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Ketuk untuk opsi lainnya."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Aksesori audio tidak didukung"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Tap untuk info selengkapnya"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debugging USB terhubung"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Ketuk untuk menonaktifkan debug USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pilih untuk menonaktifkan debugging USB."</string>
@@ -1618,7 +1615,7 @@
     <string name="package_installed_device_owner" msgid="6875717669960212648">"Diinstal oleh admin Anda"</string>
     <string name="package_updated_device_owner" msgid="1847154566357862089">"Diupdate oleh admin Anda"</string>
     <string name="package_deleted_device_owner" msgid="2307122077550236438">"Dihapus oleh admin Anda"</string>
-    <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu meningkatkan masa pakai baterai, penghemat baterai mengurangi kinerja perangkat dan membatasi getaran, layanan lokasi, dan kebanyakan data latar belakang. Email, perpesanan, dan aplikasi lain yang mengandalkan sinkronisasi mungkin tidak diperbarui kecuali jika dibuka.\n\nPenghemat baterai otomatis nonaktif jika perangkat diisi dayanya."</string>
+    <string name="battery_saver_description" msgid="1960431123816253034">"Untuk membantu meningkatkan masa pakai baterai, penghemat baterai mengurangi kinerja perangkat dan membatasi getaran, layanan lokasi, dan sebagian besar data latar belakang. Email, pesan, dan aplikasi lain yang mengandalkan sinkronisasi mungkin tidak diperbarui kecuali jika dibuka.\n\nPenghemat baterai otomatis nonaktif jika perangkat diisi dayanya."</string>
     <string name="data_saver_description" msgid="6015391409098303235">"Untuk membantu mengurangi penggunaan data, Penghemat Data mencegah beberapa aplikasi mengirim atau menerima data di latar belakang. Aplikasi yang sedang digunakan dapat mengakses data, tetapi frekuensinya agak lebih jarang. Misalnya saja, gambar hanya akan ditampilkan setelah disentuh."</string>
     <string name="data_saver_enable_title" msgid="4674073932722787417">"Aktifkan Penghemat Data?"</string>
     <string name="data_saver_enable_button" msgid="7147735965247211818">"Aktifkan"</string>
@@ -1746,8 +1743,8 @@
     <string name="time_picker_prompt_label" msgid="7588093983899966783">"Ketik waktu"</string>
     <string name="time_picker_text_input_mode_description" msgid="4148166758173708199">"Beralih ke mode masukan teks untuk masukan waktu."</string>
     <string name="time_picker_radial_mode_description" msgid="4953403779779557198">"Beralih ke mode jam untuk masukan waktu."</string>
-    <string name="autofill_picker_accessibility_title" msgid="8469043291648711535">"Opsi Isiotomatis"</string>
-    <string name="autofill_save_accessibility_title" msgid="7244365268417107822">"Simpan untuk Isiotomatis"</string>
+    <string name="autofill_picker_accessibility_title" msgid="8469043291648711535">"Opsi IsiOtomatis"</string>
+    <string name="autofill_save_accessibility_title" msgid="7244365268417107822">"Simpan untuk IsiOtomatis"</string>
     <string name="autofill_error_cannot_autofill" msgid="7402758580060110371">"Konten tidak dapat diisi otomatis"</string>
     <string name="autofill_save_title" msgid="3345527308992082601">"Simpan ke &lt;b&gt;<xliff:g id="LABEL">%1$s</xliff:g>&lt;/b&gt;?"</string>
     <string name="autofill_save_title_with_type" msgid="8637809388029313305">"Simpan <xliff:g id="TYPE">%1$s</xliff:g> ke &lt;b&gt;<xliff:g id="LABEL">%2$s</xliff:g>&lt;/b&gt;?"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index e37862b..281faf3 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Tilkynningar"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Kynningarútgáfa fyrir verslanir"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-tenging"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Forrit sem keyra í bakgrunni"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> keyrir í bakgrunni"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> forrit keyra í bakgrunni"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Ýttu til að fá upplýsingar um rafhlöðu- og gagnanotkun"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Örugg stilling"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android kerfið"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Skipta yfir í persónulegt snið"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB fyrir MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Tengt við USB-aukabúnað"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Ýttu til að sjá fleiri valkosti."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Hljóðaukabúnaður er ekki studdur"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Ýttu til að fá frekari upplýsingar"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-villuleit tengd"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Ýttu til að slökkva á USB-villuleit."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 8057a06..9541111 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Avvisi"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo retail"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Connessione USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"App in esecuzione in background"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"L\'app <xliff:g id="APP_NAME">%1$s</xliff:g> è in esecuzione in background"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> app sono in esecuzione in background"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tocca per conoscere i dettagli sull\'utilizzo dei dati e della batteria"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modalità provvisoria"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Passa al profilo personale"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB per la modalità MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Collegato a un accessorio USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Tocca per altre opzioni."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Accessorio audio non supportato"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Tocca per ulteriori informazioni"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Debug USB collegato"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tocca per disattivare il debug USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleziona per disattivare il debug USB."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 504d3ad..a087430 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -271,16 +271,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"התראות"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"הדגמה לקמעונאים"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"‏חיבור USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"אפליקציות שפועלות ברקע"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> פועלת ברקע"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> אפליקציות פועלות ברקע"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"הקש לקבלת פרטים על צריכה של נתונים וסוללה"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="RIGHT_SIDE">%2$s</xliff:g>, <xliff:g id="LEFT_SIDE">%1$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"מצב בטוח"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏מערכת Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"עבור ל\'אישי\'"</string>
@@ -1223,6 +1218,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏USB ל-MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"‏מחובר לאביזר USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"הקש לקבלת אפשרויות נוספות."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏ניפוי באגים של USB מחובר"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"‏הקש כדי להשבית ניפוי באגים של USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"‏בחר להשבית ניפוי באגים ב-USB."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 4f18bcb..2c1b9f4 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"通知"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"販売店デモ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB 接続"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"バックグラウンドで実行中のアプリ"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」がバックグラウンドで実行中です"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> 個のアプリがバックグラウンドで実行中です"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"タップすると、電池やデータの使用量を詳しく確認できます"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>、<xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"セーフモード"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Androidシステム"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"個人用に切り替える"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USBをMIDIに使用"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USBアクセサリを接続しました"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"タップしてその他のオプションを表示します。"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USBデバッグが接続されました"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"タップして USB デバッグを無効にします。"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USBデバッグを無効にする場合に選択します。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 31cd59b..d7183bc 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"გაფრთხილებები"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"დემო-რეჟიმი საცალო მოვაჭრეებისთვის"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB კავშირი"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"ფონურ რეჟიმში გაშვებული აპები"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> გაშვებულია ფონურ რეჟიმში"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"ფონურ რეჟიმში გაშვებულია <xliff:g id="NUMBER">%1$d</xliff:g> აპი"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"შეეხეთ ბატარეისა და მონაცემების მოხმარების შესახებ დეტალური ინფორმაციისთვის"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"უსაფრთხო რეჟიმი"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-ის სისტემა"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"პირად პროფილზე გადართვა"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI-სთვის"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"დაკავშირებულია USB აქსესუართან"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"შეეხეთ დამატებითი ვარიანტების სანახავად."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"აუდიო აქსესუარი მხარდაუჭერელია"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"შეეხეთ დამატებითი ინფორმაციისთვის"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB გამართვა შეერთებულია"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"შეეხეთ USB-გამართვის გასათიშად."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"მონიშნეთ რათა შეწყვიტოთ USB-ის გამართვა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index c512e43..842cd3a 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Дабылдар"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Бөлшек саудаға арналған демо нұсқасы"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB байланысы"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Фонда жұмыс істеп тұрған қолданбалар"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы фонда жұмыс істеп тұр"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> қолданба фонда жұмыс істеп тұр"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Батарея мен деректер трафигі туралы мәліметтер алу үшін түртіңіз"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Қауіпсіз режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android жүйесі"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Жекеге ауысу"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI режиміне арналған USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB жабдығына қосылған"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Қосымша опциялар үшін түртіңіз."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB жөндеу қосылған"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB түзетуін өшіру үшін түртіңіз."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 64306fd..a42f777 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ការ​ជូនដំណឹង"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"របៀបដាក់បង្ហាញក្នុងហាង"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"ការ​តភ្ជាប់ USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"កម្មវិធីដែលកំពុងដំណើរការនៅផ្ទៃខាងក្រោយ"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> កំពុងដំណើរការនៅផ្ទៃខាងក្រោយ"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"កម្មវិធី <xliff:g id="NUMBER">%1$d</xliff:g> កំពុងដំណើរការនៅផ្ទៃខាងក្រោយ"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"ចុចដើម្បីទទួលបានព័ត៌មានលម្អិតអំពីការប្រើប្រាស់ថ្ម និងទិន្នន័យ"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"របៀប​​​សុវត្ថិភាព"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ប្រព័ន្ធ​​ Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"ប្តូរទៅផ្ទាល់ខ្លួន"</string>
@@ -1185,6 +1180,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB សម្រាប់ MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"បាន​ភ្ជាប់​ឧបករណ៍​យូអេសប៊ី"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"ប៉ះសម្រាប់ជម្រើសជាច្រើនទៀត"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"បាន​ភ្ជាប់​ការ​កែ​កំហុស​យូអេសប៊ី"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"ប៉ះដើម្បីបិទដំណើរការកែកំហុសយូអេសប៊ី"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"ជ្រើស​ ដើម្បី​បិទ​ការ​កែ​កំហុស​យូអេសប៊ី។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index aaabd91..fbd51b9 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ಎಚ್ಚರಿಕೆಗಳು"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"ರಿಟೇಲ್ ಡೆಮೋ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB ಸಂಪರ್ಕ"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿವೆ"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿದೆ"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿವೆ"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"ಬ್ಯಾಟರಿ ಮತ್ತು ಡೇಟಾ ಬಳಕೆಯ ವಿವರಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"ಸುರಕ್ಷಿತ ಮೋಡ್"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android ಸಿಸ್ಟಂ"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"ವೈಯಕ್ತಿಕಗೆ ಬದಲಿಸಿ"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI ಗೆ USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB ಪರಿಕರಕ್ಕೆ ಸಂಪರ್ಕಗೊಂಡಿದೆ"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗೆ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ಡೀಬಗಿಂಗ್‌‌ ಸಂಪರ್ಕ"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ಡೀಬಗ್‌ ಮಾಡುವಿಕೆಯನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ab61857..bbddc24 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"알림"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"소매 데모"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB 연결"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"백그라운드에서 실행 중인 앱"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱이 백그라운드에서 실행 중"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g>개의 앱이 백그라운드에서 실행 중"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"탭하여 배터리 및 데이터 사용량에 관한 세부정보 보기"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"안전 모드"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 시스템"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"개인으로 전환"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI용 USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB 액세서리에 연결됨"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"옵션을 더 보려면 탭하세요."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB 디버깅 연결됨"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB 디버깅을 사용하지 않으려면 탭하세요."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB 디버깅을 사용하지 않으려면 선택합니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index a24bd7f..f5f48ad 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Эскертүүлөр"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Чекене соода дүкөнү үчүн демо режим"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB аркылуу туташуу"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Фондо иштеп жаткан колдонмолор"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосу фондо иштөөдө"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> колдонмо фондо иштөөдө"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Батареянын кубаты жана Интернеттин колдонулушу жөнүндө билүү үчүн таптап коюңуз"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Коопсуз режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android тутуму"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Жеке профилге которулуу"</string>
@@ -283,7 +278,7 @@
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"байланыштарыңызды көрүүгө"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Жайгашкан жер"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"түзмөктүн жайгашкан жерин аныктоого"</string>
-    <string name="permgrouplab_calendar" msgid="5863508437783683902">"Күнбарак"</string>
+    <string name="permgrouplab_calendar" msgid="5863508437783683902">"Жылнаама"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"жылнаамаңызды пайдалануу"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS билдирүүлөрдү жиберүү жана көрсөтүү"</string>
@@ -838,9 +833,9 @@
     <string name="autofill_parish" msgid="8202206105468820057">"Пэриш"</string>
     <string name="autofill_area" msgid="3547409050889952423">"Аймак"</string>
     <string name="autofill_emirate" msgid="2893880978835698818">"Эмират"</string>
-    <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"желе бүктөмөлүрүңүздү жана тарыхыңызды окуу"</string>
+    <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"кыстармаларыңыз менен издөө таржымалыңызды карап көрүңүз"</string>
     <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Колдонмого Серепчи ачкан URLдердин тарыхын жана Серепчинин бүктөмөлөрүн окууга уруксат берет. Эскертүү: бул уруксат үчүнчү тараптык интернет-серепчилерге, же интернетке кирүү мүмкүнчүлүгү бар колдонмолорго таасир этпеши мүмкүн."</string>
-    <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"желе бүктөмөлөрүн жана тарыхын жазуу"</string>
+    <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"кыстармалар жана издөө таржымалын өзгөртүү"</string>
     <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Колдонмого планшетиңизде сакталган Серепчинин тарыхын жана Серепчинин бүктөмөлөрүн өзгөртүү уруксатын берет. Бул колдонмого Серепчинин берилиштерин өчүрүү же өзгөртүү уруксатын берет. Эскертүү: бул уруксат үчүнчү тараптык интернет-серепчилерге, же интернетке кирүү мүмкүнчүлүгү бар колдонмолорго таасир этпеши мүмкүн."</string>
     <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Колдонмого Серепчиңиздин таржымалын же сыналгыңызда сакталган кыстармаларды өзгөртүү мүмкүнчүлүгүн берет. Ушуну менен, колдонмо Серепчи дайындарын тазалап же өзгөртө алат. Эскертүү: бул уруксат үчүнчү жактын серепчилери же башка желеде серептөө мүмкүнчүлүгү бар колдонмолор аркылуу иштетилбеши керек."</string>
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Колдонмого телефонуңузда сакталган Серепчинин тарыхын жана Серепчинин бүктөмөлөрүн өзгөртүү уруксатын берет. Бул колдонмого Серепчинин берилиштерин өчүрүү же өзгөртүү уруксатын берет. Эскертүү: бул уруксат үчүнчү тараптык интернет-серепчилерге, же интернетке кирүү мүмкүнчүлүгү бар колдонмолорго таасир этпеши мүмкүн."</string>
@@ -1128,7 +1123,7 @@
     <string name="wifi_connect_default_application" msgid="7143109390475484319">"Колдонмо"</string>
     <string name="wifi_p2p_dialog_title" msgid="97611782659324517">"Wi-Fi Direct"</string>
     <string name="wifi_p2p_turnon_message" msgid="2909250942299627244">"Wi-Fi Дайректи иштетүү. Бул Wi-Fi клиентти/хотспотту өчүрөт."</string>
-    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Дайрект иштетилбеди."</string>
+    <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct иштетилген жок."</string>
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct иштөөдө"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="8064677407830620023">"Жөндөөлөрдү ачуу үчүн таптап коюңуз"</string>
     <string name="accept" msgid="1645267259272829559">"Кабыл алуу"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI үчүн USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB аксессуарга байланышты"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Кошумча параметрлерди ачуу үчүн таптап коюңуз."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Мүчүлүштүктөрдү USB аркылуу оңдоо иштетилген"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Мүчүлштктрдү USB аркл оңдну өчр үчн тийп коюңуз."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
@@ -1351,7 +1350,7 @@
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"Айнуу"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Жок кылуу"</string>
     <string name="keyboardview_keycode_done" msgid="1992571118466679775">"Даяр"</string>
-    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Тартип алмаштыруу"</string>
+    <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"Режимди өзгөртүү"</string>
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Кирүү"</string>
     <string name="activitychooserview_choose_application" msgid="2125168057199941199">"Колдонмо тандоо"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index d162fe0..bf1ef11 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ການເຕືອນ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"ເດໂມສຳລັບຮ້ານຂາຍ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"ການເຊື່ອມຕໍ່ USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"ແອັບທີ່ກຳລັງເຮັດວຽກໃນພື້ນຫຼັງ"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> ກຳລັງເຮັດວຽກໃນພື້ນຫຼັງ"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"ແອັບ <xliff:g id="NUMBER">%1$d</xliff:g> ແອັບກຳລັງເຮັດວຽກໃນພື້ນຫຼັງ"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"ແຕະເພື່ອເບິ່ງລາຍລະອຽດການນຳໃຊ້ແບັດເຕີຣີ ແລະ ອິນເຕີເນັດ"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ລະບົບ Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"ສະລັບໄປໂປຣໄຟລ໌ສ່ວນຕົວ"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB ສຳ​ລັບ MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"ເຊື່ອມຕໍ່ກັບອຸປະກອນເສີມ USB ແລ້ວ"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"ແຕະເພື່ອເບິ່ງຕົວເລືອກເພີ່ມເຕີມ."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"ເຊື່ອມຕໍ່ການດີບັ໊ກຜ່ານ USB ແລ້ວ"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"ແຕະເພື່ອປິດການດີບັກຜ່ານ USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"ເລືອກເພື່ອປິດການດີບັ໊ກຜ່ານ USB."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 0a62d62..d8c292e 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -271,16 +271,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Įspėjimai"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstracinė versija mažmenininkams"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB jungtis"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Programos, veikiančios fone"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ veikia fone"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Programos (<xliff:g id="NUMBER">%1$d</xliff:g>) veikia fone"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Palieskite ir sužinokite išsamios informacijos apie akumuliatoriaus bei duomenų naudojimą"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Saugos režimas"</string>
     <string name="android_system_label" msgid="6577375335728551336">"„Android“ sistema"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Perjungti į asmeninį režimą"</string>
@@ -1223,6 +1218,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB (MIDI)"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Prijungta prie USB priedo"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Palieskite, kad būtų rodoma daugiau parinkčių."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB derinimas prijungtas"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Palieskite, kad išjungtumėte USB derinimą."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pasirinkite, kas išjungtumėte USB derinimą."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 3bcce6f..68a2299 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -268,16 +268,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Brīdinājumi"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstrācijas versija veikaliem"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB savienojums"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Lietotnes, kas darbojas fonā"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Lietotne <xliff:g id="APP_NAME">%1$s</xliff:g> darbojas fonā"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> lietotnes darbojas fonā"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Pieskarieties, lai skatītu detalizētu informāciju par akumulatora un datu lietojumu"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Drošais režīms"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android sistēma"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Pārslēgt personīgo profilu"</string>
@@ -1203,6 +1198,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB savienojums MIDI režīmā"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ir izveidots savienojums ar USB piederumu."</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Pieskarieties, lai skatītu citas iespējas."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB atkļūdošana ir pievienota."</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Pieskarieties, lai atspējotu USB atkļūdošanu."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Atlasiet, lai atspējotu USB atkļūdošanu."</string>
diff --git a/core/res/res/values-mcc204/config.xml b/core/res/res/values-mcc204/config.xml
new file mode 100644
index 0000000..790f768
--- /dev/null
+++ b/core/res/res/values-mcc204/config.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <bool name="config_use_sim_language_file">true</bool>
+
+</resources>
diff --git a/core/res/res/values-mcc310-mnc004/config.xml b/core/res/res/values-mcc310-mnc004/config.xml
index 63431a4..3049488 100755
--- a/core/res/res/values-mcc310-mnc004/config.xml
+++ b/core/res/res/values-mcc310-mnc004/config.xml
@@ -36,4 +36,7 @@
     <bool name="config_auto_attach_data_on_creation">false</bool>
 
     <string translatable="false" name="prohibit_manual_network_selection_in_gobal_mode">true</string>
+
+    <bool name="config_use_sim_language_file">true</bool>
+
 </resources>
diff --git a/core/res/res/values-mcc311-mnc480/config.xml b/core/res/res/values-mcc311-mnc480/config.xml
index a210f5b..6f85081 100755
--- a/core/res/res/values-mcc311-mnc480/config.xml
+++ b/core/res/res/values-mcc311-mnc480/config.xml
@@ -62,4 +62,6 @@
 
     <string translatable="false" name="prohibit_manual_network_selection_in_gobal_mode">true</string>
 
+    <bool name="config_use_sim_language_file">true</bool>
+
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b5e8c90..ae79a4a 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Предупредувања"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Демонстрација за малопродажба"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-врска"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Апликациите се извршуваат во заднина"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> се извршува во заднина"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> апликации се извршуваат во заднина"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Допрете за детали за батеријата и потрошениот сообраќај"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безбеден режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Систем Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Префрлете на личен профил"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"УСБ за МИДИ"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Поврзан со УСБ додаток"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Допрете за повеќе опции."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Поврзано е отстранување грешки преку УСБ"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Допрете за да се оневозможи отстранувањето грешки преку USB."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 5dbb334..c1fc989 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"അലേർട്ടുകൾ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"റീട്ടെയിൽ ഡെമോ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB കണക്ഷൻ"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"ആപ്പുകൾ പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുന്നു"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുന്നു"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> ആപ്പുകൾ പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുന്നു"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"ബാറ്ററി, ഡാറ്റ ഉപയോഗം എന്നിവയുടെ വിശദാംശങ്ങളറിയാൻ ടാപ്പുചെയ്യുക"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"സുരക്ഷിത മോഡ്"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android സിസ്റ്റം"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"വ്യക്തിഗത പ്രൊഫൈലിലേക്ക് മാറുക"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-യ്‌ക്കായുള്ള USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"ഒരു USB ആക്‌സസ്സറി കണക്റ്റുചെയ്‌തു"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് ടാപ്പുചെയ്യുക."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ഡീബഗ്ഗിംഗ് കണക്‌റ്റുചെയ്‌തു"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ഡീബഗ്ഗിംഗ് പ്രവർത്തനരഹിതമാക്കാൻ ടാപ്പുചെയ്യുക."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 765aa5d..3913964 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Сануулга"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Жижиглэнгийн жишээ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB холболт"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Цаана ажиллаж буй апп"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> цаана ажиллаж байна"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> апп цаана ажиллаж байна"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Батерей, дата ашиглалтын талаар дэлгэрэнгүй мэдээллийг харахын тулд товшино уу"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Аюулгүй горим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Андройд систем"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"\"Хувийн\" руу шилжих"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI-ийн USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB төхөөрөмжид холбогдов"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Бусад сонголтыг харахын тулд товшино уу."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB дебаг холбогдсон"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB-н алдаа засварлахыг идэвхгүй болгохын тулд товшино уу."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB дебаг хийхийг идэвхгүй болгох бол сонгоно уу."</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 4191828..1801664 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"सूचना"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"किरकोळ डेमो"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB कनेक्‍शन"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"अॅप्‍स बॅकग्राउंडमध्‍ये चालू आहेत"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> बॅकग्राउंडमध्‍ये चालू आहे"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> अॅप्‍स बॅकग्राउंडमध्‍ये चालू आहेत"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"बॅटरी आणि डेटा वापराच्‍या तपशीलांसाठी टॅप करा"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android सिस्‍टम"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"वैयक्तिकवर स्विच करा"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI साठी USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB उपसाधनावर कनेक्ट केले"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"अधिक पर्यायांसाठी टॅप करा."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डीबग करणे कनेक्‍ट केले"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB डीबग करणे अक्षम करण्यासाठी टॅप करा."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index d4cc2d3..27095c5 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Makluman"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Tunjuk cara runcit"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Sambungan USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apl yang berjalan di latar belakang"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> sedang berjalan di latar belakang"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> apl sedang berjalan di latar belakang"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Ketik untuk mendapatkan butiran tentang penggunaan kuasa bateri dan data"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod selamat"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Beralih kepada Peribadi"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB untuk MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Disambungkan kepada aksesori USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Ketik untuk mendapatkan lagi pilihan."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Penyahpepijatan USB disambungkan"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Ketik untuk melumpuhkan penyahpepijatan USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Pilih untuk melumpuhkan penyahpepijatan USB."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 1d89730..5d97ba8 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"သတိပေးချက်များ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"လက်လီအရောင်းဆိုင် သရုပ်ပြမှု"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB ချိတ်ဆက်မှု"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"နောက်ခံတွင် ပွင့်နေသော အက်ပ်များ"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> သည် နောက်ခံတွင် ပွင့်နေပါသည်"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"အက်ပ် <xliff:g id="NUMBER">%1$d</xliff:g> ခုသည် နောက်ခံတွင် ပွင့်နေပါသည်"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"ဘက်ထရီနှင့် ဒေတာအသုံးပြုမှု အသေးစိတ်ကို ကြည့်ရန် တို့ပါ"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>၊ <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"အန္တရာယ်ကင်းမှု စနစ်(Safe mode)"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android စနစ်"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"ကိုယ်ပိုင်သီးသန့်အဖြစ် ပြောင်းပါ"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI အတွက် USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USBတွဲဖက်ပစ္စည်းအား ချိတ်ဆက်ထားသည်"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"နောက်ထပ်ရွေးချယ်စရာများအတွက် တို့ပါ။"</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"အသံ ဆက်စပ်ပစ္စည်းကို မပံ့ပိုးပါ"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"နောက်ထပ် အချက်အလက်များအတွက် တို့ပါ"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB အမှားစစ်ခြင်းအား ချိတ်ဆက်ထားသည်"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ဆက်သွယ်ရေးစနစ်ကို ပိတ်ရန် တို့ပါ။"</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index ab32ff8..e19a131 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Varsler"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Butikkdemo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-tilkobling"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apper kjører i bakgrunnen"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> kjører i bakgrunnen"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> apper kjører i bakgrunnen"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Trykk for detaljer om batteri- og databruk"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Sikkermodus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Bytt til den personlige profilen"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB for MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Koblet til et USB-tilbehør"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Trykk for å få flere alternativ."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-feilsøking tilkoblet"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Trykk for å slå av feilsøking via USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Velg for å deaktivere USB-debugging."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 33466bc..82b5c04 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"अलर्टहरू"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"खुद्रा बिक्री सम्बन्धी डेमो"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB जडान"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"पृष्ठभूमिमा चल्ने अनुप्रयोगहरू"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> पृष्ठभूमिमा चल्दैछ"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> अनुप्रयोगहरू पृष्ठभूमिमा चल्दैछन्"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"ब्याट्री र डेटा प्रयोग सम्बन्धी विवरणहरूका लागि ट्याप गर्नुहोस्"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"सुरक्षित मोड"</string>
     <string name="android_system_label" msgid="6577375335728551336">"एन्ड्रोइड प्रणाली"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"व्यक्तिगत प्रोफाइलमा स्विच गर्नुहोस्"</string>
@@ -1189,6 +1184,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI को लागि USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB सहायकमा जोडिएको छ"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"थप विकल्पहरूका लागि ट्याप गर्नुहोस्।"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB डिबग गर्ने जडित छ"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB डिबगिङलाई असक्षम गर्न ट्याप गर्नुहोस्।"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB डिबगिङ असक्षम पार्न चयन गर्नुहोस्।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index c82219c..0d7d8c7 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Meldingen"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo voor de detailhandel"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-verbinding"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apps uitgevoerd op achtergrond"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> wordt uitgevoerd op de achtergrond"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> apps worden uitgevoerd op de achtergrond"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tik voor informatie over batterij- en datagebruik"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Veilige modus"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-systeem"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Overschakelen naar persoonlijk profiel"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB voor MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Aangesloten op een USB-accessoire"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Tik voor meer opties."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Audioaccessoire niet ondersteund"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Tik voor meer informatie"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-foutopsporing verbonden"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tik om USB-foutopsporing uit te schakelen."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecteer deze optie om USB-foutopsporing uit te schakelen."</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 5c606ae..14a6ba1 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ਸੁਚੇਤਨਾਵਾਂ"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"ਪ੍ਰਚੂਨ ਸਟੋਰਾਂ ਲਈ ਡੈਮੋ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB ਕਨੈਕਸ਼ਨ"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲਣ ਵਾਲੀਆਂ ਐਪਾਂ"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲ ਰਹੀ ਹੈ"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> ਐਪਾਂ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲ ਰਹੀਆਂ ਹਨ"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"ਬੈਟਰੀ ਅਤੇ ਡੈਟਾ ਉਪਯੋਗ ਸਬੰਧੀ ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"ਨਿੱਜੀ \'ਤੇ ਸਵਿੱਚ ਕਰੋ"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI ਲਈ USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"ਇੱਕ USB ਐਕਸੈਸਰੀ ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਟੈਪ ਕਰੋ।"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB ਡੀਬਗਿੰਗ ਕਨੈਕਟ ਕੀਤੀ"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB ਡੀਬੱਗਿੰਗ ਨੂੰ ਅਯੋਗ ਬਣਾਉਣ ਲਈ ਟੈਪ ਕਰੋ।"</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7386f2d..ca0464c 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -271,16 +271,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerty"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Tryb demo dla sklepów"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Połączenie USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplikacje działające w tle"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> działa w tle"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Aplikacje (<xliff:g id="NUMBER">%1$d</xliff:g>) działają w tle"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Kliknij, by wyświetlić szczegóły wykorzystania baterii i transmisji danych"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Tryb awaryjny"</string>
     <string name="android_system_label" msgid="6577375335728551336">"System Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Włącz profil osobisty"</string>
@@ -1223,6 +1218,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB w trybie MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Podłączono akcesorium USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Kliknij, by wyświetlić więcej opcji."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Podłączono moduł debugowania USB"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Kliknij, by wyłączyć debugowanie USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Wybierz, aby wyłączyć debugowanie USB."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index d5dc395..fc58d2c 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstração na loja"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Conexão USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apps sendo executados em segundo plano"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está sendo executado em segundo plano"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> apps estão sendo executados em segundo plano"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tocar para ver detalhes sobre a bateria e o uso de dados"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Alternar para \"Pessoal\""</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a um acessório USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Toque para ver mais opções."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Acessório de áudio não compatível"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Toque para mais informações"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração do USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 1f297c2..d8395bd 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstração para retalho"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Ligação USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplicações em execução em segundo plano"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"A aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> está a ser executada em segundo plano"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicações estão a ser executadas em segundo plano"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Toque para obter detalhes acerca da utilização da bateria e dos dados"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo seguro"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Mudar para pessoal"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ligado a um acessório USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Toque para obter mais opções."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Acessório de áudio não suportado"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Toque para obter mais informações"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB ligada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Seleccione para desativar depuração USB."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d5dc395..fc58d2c 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alertas"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstração na loja"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Conexão USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Apps sendo executados em segundo plano"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"O app <xliff:g id="APP_NAME">%1$s</xliff:g> está sendo executado em segundo plano"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> apps estão sendo executados em segundo plano"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tocar para ver detalhes sobre a bateria e o uso de dados"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modo de segurança"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistema Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Alternar para \"Pessoal\""</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectado a um acessório USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Toque para ver mais opções."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Acessório de áudio não compatível"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Toque para mais informações"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depuração USB conectada"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Toque para desativar a depuração do USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selecione para desativar a depuração USB."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 3a2c38d..0c16186 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -268,16 +268,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Alerte"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstrație comercială"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Conexiune USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplicațiile rulează în fundal"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> rulează în fundal"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> aplicații rulează în fundal"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Atingeți pentru mai multe detalii privind bateria și utilizarea datelor"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mod sigur"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistemul Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Comutați la Personal"</string>
@@ -1203,6 +1198,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"Conexiune USB pentru MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Conectat la un accesoriu USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Atingeți pentru mai multe opțiuni."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Accesoriul audio nu este acceptat"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Atingeți pentru mai multe informații"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Depanarea USB este conectată"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Atingeți ca să dezactivați remedierea erorilor prin USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Selectați pentru a dezactiva depanarea USB."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 0bc71eb..7e6a8da 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -271,16 +271,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Уведомления"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Деморежим для магазина"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-подключение"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Приложения, работающие в фоновом режиме"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" работает в фоновом режиме"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Несколько приложений (<xliff:g id="NUMBER">%1$d</xliff:g>) работает в фоновом режиме"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Нажмите, чтобы увидеть данные об энергопотреблении и объеме трафика"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безопасный режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Перейти в личный профиль"</string>
@@ -1223,6 +1218,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI через USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB-устройство подключено"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Нажмите, чтобы показать дополнительные параметры."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отладка по USB разрешена"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Нажмите, чтобы отключить отладку по USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Нажмите, чтобы отключить отладку USB."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index b7e695a..33c384e 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"ඇඟවීම්"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"සිල්ලර ආදර්ශනය"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB සම්බන්ධතාවය"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"පසුබිමින් ධාවනය වන යෙදුම්"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> පසුබිමින් ධාවනය වේ"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"යෙදුම් <xliff:g id="NUMBER">%1$d</xliff:g>ක් පසුබිමින් ධාවනය වේ"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"බැටරි හා දත්ත භාවිතය පිළිබඳව විස්තර සඳහා තට්ටු කරන්න"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"ආරක්‍ෂිත ආකාරය"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android පද්ධතිය"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"පුද්ගලික වෙත මාරු වන්න"</string>
@@ -1185,6 +1180,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI සඳහා USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB මෙවලමකට සම්බන්ධිතයි"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"තවත් විකල්ප සඳහා තට්ටු කරන්න."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB නිදොස්කරණය සම්බන්ධිතයි"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB නිදොස්කරණය අබල කිරීමට තට්ටු කරන්න."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB නිදොස්කරණය අබල කිරීමට තෝරන්න."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 018ea4e..0bc8164 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -96,7 +96,7 @@
     <string name="RestrictedOnNormalTitle" msgid="3179574012752700984">"Žiadne hlasové hovory"</string>
     <string name="RestrictedOnAllVoiceTitle" msgid="158800171499150681">"Hlasové ani tiesňové volania nie sú k dispozícii"</string>
     <string name="RestrictedOnDataContent" msgid="8997474569390996587">"Váš operátor dočasne pozastavil dátovú službu na tomto mieste"</string>
-    <string name="RestrictedOnEmergencyContent" msgid="4573217945494650061">"Váš operátor dočasne pozastavil núdzové hovory z tohto miesta"</string>
+    <string name="RestrictedOnEmergencyContent" msgid="4573217945494650061">"Váš operátor v tejto oblasti dočasne pozastavil tiesňové volania"</string>
     <string name="RestrictedOnNormalContent" msgid="1579434198284512182">"Váš operátor dočasne pozastavil hlasové hovory z tohto miesta"</string>
     <string name="RestrictedOnAllVoiceContent" msgid="5243580774142557047">"Váš operátor v tejto oblasti dočasne blokuje hlasové a tiesňové hovory"</string>
     <string name="NetworkPreferenceSwitchTitle" msgid="4008877505368566980">"Nepodarilo sa pripojiť k sieti"</string>
@@ -271,16 +271,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Upozornenia"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Predajná ukážka"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Pripojenie USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplikácie sú spustené na pozadí"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Aplikácia <xliff:g id="APP_NAME">%1$s</xliff:g> je spustená na pozadí"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Niekoľko aplikácií (<xliff:g id="NUMBER">%1$d</xliff:g>) je spustených na pozadí"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Klepnutím zobrazíte podrobnosti o batérii a spotrebe dát"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Núdzový režim"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Systém Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Prepnúť na osobný"</string>
@@ -1223,6 +1218,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB na pripojenie zariadenia MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Pripojené k periférnemu zariadeniu USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Klepnutím zobrazíte ďalšie možnosti."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Zvukové príslušenstvo nie je podporované"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Ďalšie informácie zobrazíte klepnutím"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ladenie cez USB pripojené"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Klepnutím zakážete ladenie cez USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Výberom zakážete ladenie USB."</string>
@@ -1825,7 +1822,7 @@
     <string name="etws_primary_default_message_earthquake" msgid="5541962250262769193">"Zachovajte pokoj a vyhľadajte úkryt v okolí."</string>
     <string name="etws_primary_default_message_tsunami" msgid="1887685943498368548">"Okamžite začnite evakuáciu z prímorských a nábrežných oblastí na bezpečnejšie miesto, napríklad do vyššie položených regiónov."</string>
     <string name="etws_primary_default_message_earthquake_and_tsunami" msgid="998797956848445862">"Zachovajte pokoj a vyhľadajte úkryt v okolí."</string>
-    <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test núdzových správ"</string>
+    <string name="etws_primary_default_message_test" msgid="2709597093560037455">"Test tiesňových správ"</string>
     <string name="etws_primary_default_message_others" msgid="6293148756130398971"></string>
     <string name="mmcc_authentication_reject" msgid="7729819349669603406">"SIM karta je zakázaná"</string>
     <string name="mmcc_imsi_unknown_in_hlr" msgid="6321202257374418726">"SIM karta nie je k dispozícii"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 729612f..8ac1b4d 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -271,16 +271,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Opozorila"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Predstavitev za maloprodajo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Povezava USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplikacije se izvajajo v ozadju"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> se izvaja v ozadju"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Več aplikacij (<xliff:g id="NUMBER">%1$d</xliff:g>) se izvaja v ozadju"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Dotaknite se za prikaz podrobnosti porabe akumulatorja in prenosa podatkov"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Varni način"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistem Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Preklop na osebni profil"</string>
@@ -1223,6 +1218,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB za MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Priključen na dodatek USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Dotaknite se za več možnosti."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Iskanje napak prek USB je povezano"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Dotaknite se za izklop odpravljanja napak prek USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Izberite, če želite onemogočiti iskanje in odpravljanje napak prek vrat USB."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 563f4bd..9f2bae8 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Sinjalizimet"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demonstrimi i shitjes me pakicë"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Lidhja USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Aplikacionet që ekzekutohen në sfond"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> po ekzekutohet në sfond"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> aplikacione po ekzekutohen në sfond"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Trokit për detaje për baterinë dhe përdorimin e të dhënave"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Modaliteti i sigurisë"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Sistemi \"android\""</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Ndryshoje te \"Personale\""</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB për MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"U lidh me një ndihmës USB-je"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Trokit për më shumë opsione."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Korrigjuesi i USB-së i lidhur"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Trokit për të çaktivizuar korrigjimin e gabimeve të USB-së."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 2d2cc70..ee2c4c8 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -268,16 +268,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Обавештења"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Режим демонстрације за малопродајне објекте"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB веза"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Апликације покренуте у позадини"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> је покренута у позадини"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Апликације (<xliff:g id="NUMBER">%1$d</xliff:g>) су покренуте у позадини"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Додирните да бисте прегледали детаље о батерији и потрошњи података"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безбедни режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android систем"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Пређи на Лични профил"</string>
@@ -300,13 +295,13 @@
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"упућује телефонске позиве и управља њима"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Сензори за тело"</string>
     <string name="permgroupdesc_sensors" msgid="7147968539346634043">"приступа подацима сензора о виталним функцијама"</string>
-    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Преузима садржај прозора"</string>
+    <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"да преузима садржај прозора"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Проверава садржај прозора са којим остварујете интеракцију."</string>
-    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Укључи Истраживања додиром"</string>
+    <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"да укључи Истраживања додиром"</string>
     <string name="capability_desc_canRequestTouchExploration" msgid="7543249041581408313">"Ставке које додирнете ће бити изговорене наглас, а можете да се крећете по екрану покретима."</string>
-    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"Прати текст који уносите"</string>
+    <string name="capability_title_canRequestFilterKeyEvents" msgid="2103440391902412174">"да прати текст који уносите"</string>
     <string name="capability_desc_canRequestFilterKeyEvents" msgid="7463135292204152818">"Обухвата личне податке као што су бројеви кредитних картица и лозинке."</string>
-    <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"Управљај увећањем приказа"</string>
+    <string name="capability_title_canControlMagnification" msgid="3593493281059424855">"да управља увећањем приказа"</string>
     <string name="capability_desc_canControlMagnification" msgid="4791858203568383773">"Управља нивоом зумирања приказа и одређивањем положаја."</string>
     <string name="capability_title_canPerformGestures" msgid="7418984730362576862">"Обављање покрета"</string>
     <string name="capability_desc_canPerformGestures" msgid="8296373021636981249">"Може да додирује, листа, скупља приказ и обавља друге покрете."</string>
@@ -1053,7 +1048,7 @@
     <string name="noApplications" msgid="2991814273936504689">"Ниједна апликација не може да обавља ову радњу."</string>
     <string name="aerr_application" msgid="250320989337856518">"Апликација <xliff:g id="APPLICATION">%1$s</xliff:g> је заустављена"</string>
     <string name="aerr_process" msgid="6201597323218674729">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> је заустављен"</string>
-    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> се стално зауставља"</string>
+    <string name="aerr_application_repeated" msgid="3146328699537439573">"<xliff:g id="APPLICATION">%1$s</xliff:g> се стално зауставља(ју)"</string>
     <string name="aerr_process_repeated" msgid="6235302956890402259">"Процес <xliff:g id="PROCESS">%1$s</xliff:g> се стално зауставља"</string>
     <string name="aerr_restart" msgid="7581308074153624475">"Поново отвори апликацију"</string>
     <string name="aerr_report" msgid="5371800241488400617">"Пошаљите повратне информације"</string>
@@ -1203,6 +1198,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB за MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Повезано са USB додатком"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Додирните за још опција."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Додатна опрема за аудио садржај није подржана"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Додирните за више информација"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Отклањање грешака са USB-а је успостављено"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Додирните да бисте онемогућили отклањање грешака са USB-а."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Изаберите да бисте онемогућили отклањања грешака са USB-а."</string>
@@ -1312,7 +1309,7 @@
     <string name="vpn_lockdown_config" msgid="5099330695245008680">"Додирните да бисте подесили"</string>
     <string name="upload_file" msgid="2897957172366730416">"Одабери датотеку"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Није изабрана ниједна датотека"</string>
-    <string name="reset" msgid="2448168080964209908">"Поново постави"</string>
+    <string name="reset" msgid="2448168080964209908">"Ресетуј"</string>
     <string name="submit" msgid="1602335572089911941">"Пошаљи"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Режим рада у аутомобилу је омогућен"</string>
     <string name="car_mode_disable_notification_message" msgid="6301524980144350051">"Додирните да бисте изашли из режима рада у аутомобилу."</string>
@@ -1346,7 +1343,7 @@
     <string name="sync_really_delete" msgid="2572600103122596243">"Избриши ставке"</string>
     <string name="sync_undo_deletes" msgid="2941317360600338602">"Опозови брисања"</string>
     <string name="sync_do_nothing" msgid="3743764740430821845">"Не ради ништа за сада"</string>
-    <string name="choose_account_label" msgid="5655203089746423927">"Избор налога"</string>
+    <string name="choose_account_label" msgid="5655203089746423927">"Изаберите налог"</string>
     <string name="add_account_label" msgid="2935267344849993553">"Додај налог"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"Додај налог"</string>
     <string name="number_picker_increment_button" msgid="2412072272832284313">"Повећавање"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index c480df4..0c13829 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Varningar"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo för återförsäljare"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB-anslutning"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Appar körs i bakgrunden"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> körs i bakgrunden"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> appar körs i bakgrunden"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Tryck för information om batteri- och dataanvändning"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Säkert läge"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android-system"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Byt till din personliga profil"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB för MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ansluten till ett USB-tillbehör"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Tryck för fler alternativ."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB-felsökning ansluten"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Tryck om du vill inaktivera USB-felsökning."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Välj att inaktivera USB-felsökning."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index cec75bc..8c563a1 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -263,16 +263,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Arifa"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Onyesho la duka la rejareja"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Muunganisho wa USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Programu zinatumika chinichini"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> inatumika chinichini"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Programu <xliff:g id="NUMBER">%1$d</xliff:g> zinatumika chinichini"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Gonga ili upate maelezo kuhusu betri na matumizi ya data"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Mtindo salama"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Mfumo wa Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Badili uweke wasifu wa Binafsi"</string>
@@ -1181,6 +1176,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB kwa ajili ya MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Imeunganishwa kwa kifuasi cha USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Gonga ili upate chaguo zaidi."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Kifuasi cha sauti hakiwezi kutumika"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Gonga ili upate maelezo zaidi"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Utatuaji wa USB umeunganishwa"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Gonga ili uzime utatuaji wa USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Chagua ili kulemaza utatuaji USB."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 7062e98..45da7ef 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"விழிப்பூட்டல்கள்"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"விற்பனையாளர் டெமோ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB இணைப்பு"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"பின்னணியில் இயங்கும் பயன்பாடுகள்"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> பயன்பாடு பின்னணியில் இயங்குகிறது"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> பயன்பாடுகள் பின்னணியில் இயங்குகின்றன"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"பேட்டரி மற்றும் தரவு உபயோகம் குறித்த விவரங்களுக்கு, தட்டவும்"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"பாதுகாப்பு பயன்முறை"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android அமைப்பு"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"தனிப்பட்ட சுயவிவரத்திற்கு மாறு"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB, MIDIக்கு மட்டும்"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB துணைக்கருவியுடன் இணைக்கப்பட்டுள்ளது"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"மேலும் விருப்பங்களுக்கு, தட்டவும்."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"ஆடியோ துணைக்கருவி ஆதரிக்கப்படவில்லை"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"மேலும் தகவலுக்கு, தட்டவும்"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB பிழை திருத்தத்தை முடக்க, தட்டவும்."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 31e2721..3fbb340 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"హెచ్చరికలు"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"రిటైల్ డెమో"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB కనెక్షన్"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"నేపథ్యంలో అమలు అవుతున్న ఆప్‌లు"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> నేపథ్యంలో అమలు అవుతోంది"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> ఆప్‌లు నేపథ్యంలో అమలు అవుతున్నాయి"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"బ్యాటరీ మరియు డేటా వినియోగ వివరాల కోసం నొక్కండి"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"సురక్షిత మోడ్"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android సిస్టమ్"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"వ్యక్తిగతానికి మార్చు"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI కోసం USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB ఉపకరణానికి కనెక్ట్ చేయబడింది"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"మరిన్ని ఎంపికల కోసం నొక్కండి."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB డీబగ్గింగ్ కనెక్ట్ చేయబడింది"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB డీబగ్గింగ్‌ను నిలిపివేయడానికి నొక్కండి."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index fd7158f..2278ca8 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"การแจ้งเตือน"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"การสาธิตสำหรับผู้ค้าปลีก"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"การเชื่อมต่อ USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"แอปที่กำลังทำงานในเบื้องหลัง"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> กำลังทำงานในเบื้องหลัง"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"แอป <xliff:g id="NUMBER">%1$d</xliff:g> กำลังทำงานในเบื้องหลัง"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"แตะเพื่อดูรายละเอียดเกี่ยวกับแบตเตอรี่และปริมาณการใช้อินเทอร์เน็ต"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"โหมดปลอดภัย"</string>
     <string name="android_system_label" msgid="6577375335728551336">"ระบบ Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"เปลี่ยนไปใช้โปรไฟล์ส่วนตัว"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB สำหรับ MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"เชื่อมต่อกับอุปกรณ์เสริม USB แล้ว"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"แตะเพื่อดูตัวเลือกเพิ่มเติม"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"เชื่อมต่อการแก้ไขข้อบกพร่อง USB แล้ว"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"แตะเพื่อปิดใช้การแก้ไขข้อบกพร่องของ USB"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"เลือกเพื่อปิดใช้งานการแก้ไขข้อบกพร่อง USB"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index e58f62f..c4d40d1 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Mga Alerto"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Retail demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Koneksyon ng USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Tumatakbo ang mga app sa background"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Tumatakbo ang <xliff:g id="APP_NAME">%1$s</xliff:g> sa background"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> (na) app ang tumatakbo sa background"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"I-tap para sa mga detalye tungkol sa paggamit ng baterya at data"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Safe mode"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Lumipat sa Personal"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB para sa MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Nakakonekta sa isang accessory ng USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"I-tap para sa higit pang mga opsyon."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Konektado ang debugging ng USB"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"I-tap upang i-disable ang pag-debug ng USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Piliin upang i-disable ang debugging ng USB."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index e395435..c94fbd4 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Uyarılar"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Mağaza demo"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB bağlantısı"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Uygulamalar arka planda çalışıyor"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> arka planda çalışıyor"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> uygulama arka planda çalışıyor"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Pil ve veri kullanımı ile ilgili ayrıntılar için dokunun"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Güvenli mod"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android Sistemi"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Kişisel Profile Geç"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"MIDI için USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB aksesuarına bağlandı"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Diğer seçenekler için dokunun."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB hata ayıklaması bağlandı"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"USB hata ayıklama özelliğini devre dışı bırakmak için dokunun."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"USB hata ayıklamasını devre dışı bırakmak için tıklayın."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 09cec2a..ac36114 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -271,16 +271,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Сповіщення"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Демо-режим для роздрібної торгівлі"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"З’єднання USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Додатки, які працюють у фоновому режимі"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"Додаток <xliff:g id="APP_NAME">%1$s</xliff:g> працює у фоновому режимі"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"Додатки, які працюють у фоновому режимі: <xliff:g id="NUMBER">%1$d</xliff:g>"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Торкніться, щоб переглянути інформацію про використання заряду акумулятора та даних"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Безп. режим"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Система Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Перейти в особистий профіль"</string>
@@ -1223,6 +1218,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB для режиму MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Під’єднано до аксесуара USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Торкніться, щоб переглянути більше опцій."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Аксесуар для аудіо не підтримується"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Торкніться, щоб дізнатися більше"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Налагодження USB завершено"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Торкніться, щоб вимкнути налагодження USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Вибер., щоб вимкн. налагодж. USB."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 225faa6..4722203 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"الرٹس"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"ریٹیل ڈیمو"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"‏USB کنکشن"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"ایپس پس منظر میں چل رہی ہیں"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> پس منظر میں چل رہی ہے"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> ایپس پس منظر میں چل رہی ہیں"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"بیٹری اور ڈیٹا استعمال کے بارے میں تفصیلات کے لیے تھپتھپائیں"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>، <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"حفاظتی وضع"</string>
     <string name="android_system_label" msgid="6577375335728551336">"‏Android سسٹم"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"ذاتی پر سوئچ کریں"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"‏MIDI کیلئے USB"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"‏ایک USB لوازم سے مربوط ہے"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"مزید اختیارات کیلئے تھپتھپائیں۔"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"‏USB ڈیبگ کرنا مربوط ہو گیا"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"‏USB ڈیبگنگ کو غیر فعال کرنے کیلئے تھپتھپائیں۔"</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index 0e7d4ff..1fdfc45 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -72,7 +72,7 @@
     <string name="ClirMmi" msgid="7784673673446833091">"Chiquvchi raqami"</string>
     <string name="ColpMmi" msgid="3065121483740183974">"Qo‘ng‘iroq qiluvchining raqami"</string>
     <string name="ColrMmi" msgid="4996540314421889589">"Qo‘ng‘iroq qiluvchining raqamini cheklash"</string>
-    <string name="CfMmi" msgid="5123218989141573515">"Chaqiruvni yo‘naltirish"</string>
+    <string name="CfMmi" msgid="5123218989141573515">"Chaqiruvlarni uzatish"</string>
     <string name="CwMmi" msgid="9129678056795016867">"Chaqiruvni kutish"</string>
     <string name="BaMmi" msgid="455193067926770581">"Qo‘ng‘iroqlarni taqiqlash"</string>
     <string name="PwdMmi" msgid="7043715687905254199">"Parolni o‘zgartirish"</string>
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Ogohlantirishlar"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Demo rejim"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB orqali ulanish"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Fonda ishlayotgan ilovalar"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> fonda ishlamoqda"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> ta ilova fonda ishlamoqda"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Batareya va trafik sarfiga oid tafsilotlarni olish uchun ustiga bosing"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Xavfsiz usul"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android tizimi"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Shaxsiy profilga o‘tish"</string>
@@ -1083,15 +1078,15 @@
     <string name="dump_heap_title" msgid="5864292264307651673">"Hip-damp ma’lumotlari bilan ulashasizmi?"</string>
     <string name="dump_heap_text" msgid="4809417337240334941">"<xliff:g id="PROC">%1$s</xliff:g> jarayoni o‘zi uchun ajratilgan <xliff:g id="SIZE">%2$s</xliff:g> xotira chegarasidan o‘tib ketdi. Ilova dasturchisi bilan ulashishingiz uchun hip-damp ma’lumotlari yig‘ilib qoldi. Ehtiyot bo\'ling: ushbu hip-dampda ilova uchun foydalanishga ruxsat berilgan shaxsiy ma’lumotlaringiz bo‘lishi mumkin."</string>
     <string name="sendText" msgid="5209874571959469142">"Matn uchun amalni tanlash"</string>
-    <string name="volume_ringtone" msgid="6885421406845734650">"Jiringlaganda ovoz balandligi"</string>
+    <string name="volume_ringtone" msgid="6885421406845734650">"Jiringlaganda tovush balandligi"</string>
     <string name="volume_music" msgid="5421651157138628171">"Multimedia ovozi"</string>
     <string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"Bluetooth orqali ijro etilmoqda"</string>
     <string name="volume_music_hint_silent_ringtone_selected" msgid="8310739960973156272">"Ovozsiz rejim tanlandi"</string>
-    <string name="volume_call" msgid="3941680041282788711">"Suhbat vaqtidagi ovoz balandligi"</string>
+    <string name="volume_call" msgid="3941680041282788711">"Suhbat vaqtidagi tovush balandligi"</string>
     <string name="volume_bluetooth_call" msgid="2002891926351151534">"Kiruvchi bluetooth tovushi"</string>
     <string name="volume_alarm" msgid="1985191616042689100">"Signal ovozi"</string>
     <string name="volume_notification" msgid="2422265656744276715">"Eslatma tovushi"</string>
-    <string name="volume_unknown" msgid="1400219669770445902">"Ovoz balandligi"</string>
+    <string name="volume_unknown" msgid="1400219669770445902">"Tovush balandligi"</string>
     <string name="volume_icon_description_bluetooth" msgid="6538894177255964340">"Bluetooth tovushi"</string>
     <string name="volume_icon_description_ringer" msgid="3326003847006162496">"Rington balandligi"</string>
     <string name="volume_icon_description_incall" msgid="8890073218154543397">"Qo‘ng‘iroq tovushi balandligi"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB orqali MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB jihozga ulangan"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Boshqa parametrlarini ko‘rish uchun bosing."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Audio aksessuar ishlamaydi"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Tafsilotlar uchun bosing"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB orqali nosozliklarni tuzatish"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Faolsizlantirish uchun bu yerga bosing."</string>
     <!-- no translation found for adb_active_notification_message (8470296818270110396) -->
@@ -1474,7 +1471,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
     <string name="kg_text_message_separator" product="default" msgid="4160700433287233771">" — "</string>
     <string name="kg_reordering_delete_drop_target_text" msgid="7899202978204438708">"O‘chirish"</string>
-    <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Ovoz balandligi tavsiya etilgan darajadan ham yuqori ko‘tarilsinmi?\n\nUzoq vaqt davomida baland ovozda tinglash eshitish qobiliyatingizga salbiy ta’sir ko‘rsatishi mumkin."</string>
+    <string name="safe_media_volume_warning" product="default" msgid="2276318909314492312">"Tovush balandligi tavsiya etilgan darajadan ham yuqori qilinsinmi?\n\nUzoq vaqt davomida baland ovozda tinglash eshitish qobiliyatingizga salbiy ta’sir ko‘rsatishi mumkin."</string>
     <string name="accessibility_shortcut_warning_dialog_title" msgid="8404780875025725199">"Tezkor ishga tushirishdan foydalanilsinmi?"</string>
     <string name="accessibility_shortcut_toogle_warning" msgid="7256507885737444807">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala ovoz balandligini boshqarish tugmasini 3 soniya bosib turing.\n\n Joriy maxsus imkoniyatlar funksiyasi:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Bu funksiyani Sozlamalar &gt; Maxsus imkoniyatlar orqali o‘zgartirish mumkin."</string>
     <string name="disable_accessibility_shortcut" msgid="627625354248453445">"Tezkor ishga tushirishni o‘chirib qo‘yish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index f2ba671..c39901f 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Cảnh báo"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Giới thiệu bán lẻ"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Kết nối USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Ứng dụng đang chạy trong nền"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> đang chạy trong nền"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> ứng dụng đang chạy trong nền"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Nhấn để biết chi tiết về pin và mức sử dụng dữ liệu"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Chế độ an toàn"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Hệ thống Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Chuyển sang Cá nhân"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB cho MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Đã kết nối với phụ kiện USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Nhấn để biết thêm tùy chọn."</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Gỡ lỗi USB đã được kết nối"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Nhấn để vô hiệu hóa gỡ lỗi USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Chọn để vô hiệu hóa gỡ lỗi USB."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6e35e3f..8031be6 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"提醒"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"零售演示模式"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB 连接"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"在后台运行的应用"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g>正在后台运行"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> 个应用正在后台运行"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"点按即可详细了解电量和流量消耗情况"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>、<xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系统"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"切换到“个人”"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"正在通过 USB 连接到 MIDI 接口"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"已连接到USB配件"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"点按即可查看更多选项。"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已连接到USB调试"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"点按即可停用 USB 调试功能。"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"选择停用USB调试。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 74f4987..3dc0cd08 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"通知"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"零售示範"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB 連線"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"正在背景中執行的應用程式"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> 正在背景中執行"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> 個應用程式正在背景中執行"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"輕按即可查看電池和數據用量詳情"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>、<xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"切換至個人設定檔"</string>
@@ -701,7 +696,7 @@
     <string name="relationTypeSister" msgid="1735983554479076481">"姊妹"</string>
     <string name="relationTypeSpouse" msgid="394136939428698117">"配偶"</string>
     <string name="sipAddressTypeCustom" msgid="2473580593111590945">"自訂"</string>
-    <string name="sipAddressTypeHome" msgid="6093598181069359295">"家用"</string>
+    <string name="sipAddressTypeHome" msgid="6093598181069359295">"住宅"</string>
     <string name="sipAddressTypeWork" msgid="6920725730797099047">"公司"</string>
     <string name="sipAddressTypeOther" msgid="4408436162950119849">"其他"</string>
     <string name="quick_contacts_not_available" msgid="746098007828579688">"找不到可以查看這位聯絡人的應用程式。"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"已連接到一個 USB 配件"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"輕按即可查看更多選項。"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"輕按即可停用 USB 偵錯功能。"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"選取即可停用 USB 偵錯。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 87e98dd..2916c42 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"快訊"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"零售商示範模式"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"USB 連線"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"在背景執行的應用程式"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」正在背景執行"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> 個應用程式正在背景執行"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"輕觸即可取得電池和數據用量的詳細資料"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>、<xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"安全模式"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Android 系統"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"切換至個人設定檔"</string>
@@ -1183,6 +1178,10 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"USB MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"已連接 USB 配件"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"輕觸即可查看更多選項。"</string>
+    <!-- no translation found for usb_unsupported_audio_accessory_title (2256529893240208458) -->
+    <skip />
+    <!-- no translation found for usb_unsupported_audio_accessory_message (7811865061127547035) -->
+    <skip />
     <string name="adb_active_notification_title" msgid="6729044778949189918">"已連接 USB 偵錯工具"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"輕觸即可停用 USB 偵錯。"</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"選取以停用 USB 偵錯。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index a656e6c..9da0d4f 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -265,16 +265,11 @@
     <string name="notification_channel_alerts" msgid="4496839309318519037">"Izexwayiso"</string>
     <string name="notification_channel_retail_mode" msgid="6088920674914038779">"Idemo yokuthenga"</string>
     <string name="notification_channel_usb" msgid="9006850475328924681">"Ukuxhumeka kwe-USB"</string>
-    <!-- no translation found for notification_channel_foreground_service (6665375982962336520) -->
-    <skip />
-    <!-- no translation found for foreground_service_app_in_background (6826789589341671842) -->
-    <skip />
-    <!-- no translation found for foreground_service_apps_in_background (7150914856893450380) -->
-    <skip />
-    <!-- no translation found for foreground_service_tap_for_details (372046743534354644) -->
-    <skip />
-    <!-- no translation found for foreground_service_multiple_separator (4021901567939866542) -->
-    <skip />
+    <string name="notification_channel_foreground_service" msgid="6665375982962336520">"Izinhlelo zokusebenza zisebenza ngasemuva"</string>
+    <string name="foreground_service_app_in_background" msgid="6826789589341671842">"<xliff:g id="APP_NAME">%1$s</xliff:g> iyasebenza ngemuva"</string>
+    <string name="foreground_service_apps_in_background" msgid="7150914856893450380">"<xliff:g id="NUMBER">%1$d</xliff:g> izinhlelo zokusebenza ziyasebenza ngemuva"</string>
+    <string name="foreground_service_tap_for_details" msgid="372046743534354644">"Thepha ngemininingwane ekusetshenzisweni kwebhethri nedatha"</string>
+    <string name="foreground_service_multiple_separator" msgid="4021901567939866542">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string>
     <string name="safeMode" msgid="2788228061547930246">"Imodi ephephile"</string>
     <string name="android_system_label" msgid="6577375335728551336">"Uhlelo lwe-Android"</string>
     <string name="user_owner_label" msgid="1119010402169916617">"Shintshela komuntu siqu"</string>
@@ -1183,6 +1178,8 @@
     <string name="usb_midi_notification_title" msgid="4850904915889144654">"I-USB ye-MIDI"</string>
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"Ixhunywe ku-accessory ye-USB"</string>
     <string name="usb_notification_message" msgid="3370903770828407960">"Thepha ngezinketho eziningi."</string>
+    <string name="usb_unsupported_audio_accessory_title" msgid="2256529893240208458">"Insiza yomsindo ayisekelwa"</string>
+    <string name="usb_unsupported_audio_accessory_message" msgid="7811865061127547035">"Thepha ngolwazi olungeziwe"</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"Ukulungisa iphutha le-USB kuxhunyiwe"</string>
     <string name="adb_active_notification_message" msgid="4948470599328424059">"Thepha ukuze ukhubaze ukususa isiphazamisi se-USB."</string>
     <string name="adb_active_notification_message" product="tv" msgid="8470296818270110396">"Khetha ukuvimbela ukulungisa iphutha le-USB."</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index f3c54ba..12fa8fc 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1265,6 +1265,49 @@
     <!-- True if WallpaperService is enabled -->
     <bool name="config_enableWallpaperService">true</bool>
 
+    <!-- Enables the TimeZoneRuleManager service. This is the master switch for the updateable time
+         zone update mechanism. -->
+    <bool name="config_enableUpdateableTimeZoneRules">false</bool>
+
+    <!-- Enables APK-based time zone update triggering. Set this to false when updates are triggered
+         via external events and not by APK updates. For example, if an updater checks with a server
+         on a regular schedule.
+         [This is only used if config_enableUpdateableTimeZoneRules is true.] -->
+    <bool name="config_timeZoneRulesUpdateTrackingEnabled">false</bool>
+
+    <!-- The package of the time zone rules updater application. Expected to be the same
+         for all Android devices that support APK-based time zone rule updates.
+         A package-targeted android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
+         will be sent to the updater app if the system server detects an update to the updater or
+         data app packages.
+         The package referenced here must have the android.permission.UPDATE_TIME_ZONE_RULES
+         permission.
+         [This is only used if config_enableUpdateableTimeZoneRules and
+         config_timeZoneRulesUpdateTrackingEnabled are true.] -->
+    <string name="config_timeZoneRulesUpdaterPackage" translateable="false"></string>
+
+    <!-- The package of the time zone rules data application. Expected to be configured
+         by OEMs to reference their own priv-app APK package.
+         A package-targeted android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
+         will be sent to the updater app if the system server detects an update to the updater or
+         data app packages.
+         [This is only used if config_enableUpdateableTimeZoneRules and
+         config_timeZoneRulesUpdateTrackingEnabled are true.] -->
+    <string name="config_timeZoneRulesDataPackage" translateable="false"></string>
+
+    <!-- The allowed time in milliseconds between an update check intent being broadcast and the
+         response being considered overdue. Reliability triggers will not fire in this time.
+         [This is only used if config_enableUpdateableTimeZoneRules and
+         config_timeZoneRulesUpdateTrackingEnabled are true.] -->
+    <!-- 5 minutes -->
+    <integer name="config_timeZoneRulesCheckTimeMillisAllowed">300000</integer>
+
+    <!-- The number of times a time zone update check is allowed to fail before the system will stop
+         reacting to reliability triggers.
+         [This is only used if config_enableUpdateableTimeZoneRules and
+         config_timeZoneRulesUpdateTrackingEnabled are true.] -->
+    <integer name="config_timeZoneRulesCheckRetryCount">5</integer>
+
     <!-- Whether to enable network location overlay which allows network
          location provider to be replaced by an app at run-time. When disabled,
          only the config_networkLocationProviderPackageName package will be
@@ -1299,9 +1342,9 @@
              * Include a Service for the android.net.scoring.RECOMMEND_NETWORKS action
                protected by the BIND_NETWORK_RECOMMENDATION_SERVICE permission.
 
-         This must be set to a valid network recommendation app.
+         This must be set to a valid network recommendation app or empty.
      -->
-    <string name="config_defaultNetworkRecommendationProviderPackage" translatable="false">com.android.networkrecommendation</string>
+    <string name="config_defaultNetworkRecommendationProviderPackage" translatable="false"></string>
 
     <!-- Whether to enable Hardware FLP overlay which allows Hardware FLP to be
          replaced by an app at run-time. When disabled, only the
@@ -2886,4 +2929,8 @@
 
     <!-- Additional non-platform defined secure settings exposed to Instant Apps -->
     <string-array name="config_allowedSecureInstantAppSettings"></string-array>
+
+    <!-- Handle volume keys directly in Window Manager without passing them to the foreground app -->
+    <bool name="config_handleVolumeKeysInWindowManager">false</bool>
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 9848485..134527c 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -644,8 +644,10 @@
     <!-- Text shown when viewing channel settings for notifications related to a usb connection -->
     <string name="notification_channel_usb">USB connection</string>
 
-    <!-- Text shown when viewing channel settings for notifications related to running foreground
-        services [CHAR LIMIT=NONE] -->
+    <!-- This is the label for the notification channel settings that controls the behavior
+        of the notification about applications that are running in the background (that is,
+        perhaps confusingly, running foreground services but not the foreground UI on the screen).
+        [CHAR LIMIT=NONE] -->
     <string name="notification_channel_foreground_service">Apps running in background</string>
 
     <!-- Label for foreground service notification when one app is running. [CHAR LIMIT=NONE] -->
@@ -663,7 +665,10 @@
         data usage</string>
 
     <!-- Separator for foreground service notification content listing all apps when there
-        are multiple apps running [CHAR LIMIT=NONE] -->
+        are multiple apps running.  The left and right side may both already be compound
+        (constructed using this separator).  Should be kept as short as possible, this is
+        for summary text in the notification where there is not a lot of space.
+        [CHAR LIMIT=NONE] -->
     <string name="foreground_service_multiple_separator"><xliff:g id="left_side">%1$s</xliff:g>,
         <xliff:g id="right_side">%2$s</xliff:g></string>
 
@@ -2696,10 +2701,10 @@
     <string name="dial">Phone</string>
 
     <!-- Label for item in the text selection menu to trigger a Map app [CHAR LIMIT=20] -->
-    <string name="map">Map</string>
+    <string name="map">Maps</string>
 
     <!-- Label for item in the text selection menu to trigger a Browser app [CHAR LIMIT=20] -->
-    <string name="browse">Browse</string>
+    <string name="browse">Browser</string>
 
     <!-- If the device is getting low on internal storage, a notification is shown to the user.  This is the title of that notification. -->
     <string name="low_internal_storage_view_title">Storage space running out</string>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 2ae2ca0..690b051 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -511,6 +511,8 @@
 
     <style name="Widget.CheckedTextView">
         <item name="textAlignment">viewStart</item>
+        <item name="breakStrategy">high_quality</item>
+        <item name="hyphenationFrequency">normal</item>
     </style>
 
     <style name="Widget.TextView.ListSeparator">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 5aec3ce..8ff7f67 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -284,6 +284,12 @@
   <java-symbol type="bool" name="split_action_bar_is_narrow" />
   <java-symbol type="bool" name="config_useVolumeKeySounds" />
   <java-symbol type="bool" name="config_enableWallpaperService" />
+  <java-symbol type="bool" name="config_enableUpdateableTimeZoneRules" />
+  <java-symbol type="bool" name="config_timeZoneRulesUpdateTrackingEnabled" />
+  <java-symbol type="string" name="config_timeZoneRulesUpdaterPackage" />
+  <java-symbol type="string" name="config_timeZoneRulesDataPackage" />
+  <java-symbol type="integer" name="config_timeZoneRulesCheckTimeMillisAllowed" />
+  <java-symbol type="integer" name="config_timeZoneRulesCheckRetryCount" />
   <java-symbol type="bool" name="config_sendAudioBecomingNoisy" />
   <java-symbol type="bool" name="config_enableScreenshotChord" />
   <java-symbol type="bool" name="config_bluetooth_default_profiles" />
@@ -3022,4 +3028,5 @@
   <java-symbol type="array" name="config_allowedSystemInstantAppSettings" />
   <java-symbol type="array" name="config_allowedSecureInstantAppSettings" />
 
+  <java-symbol type="bool" name="config_handleVolumeKeysInWindowManager" />
 </resources>
diff --git a/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
new file mode 100644
index 0000000..9bbcd3d
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezone/DistroFormatVersionTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 android.app.timezone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link DistroFormatVersion}.
+ */
+// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
+public class DistroFormatVersionTest {
+
+    @Test
+    public void equalsAndHashCode() {
+        DistroFormatVersion one = new DistroFormatVersion(1, 2);
+        assertEqualsContract(one, one);
+
+        DistroFormatVersion two = new DistroFormatVersion(1, 2);
+        assertEqualsContract(one, two);
+
+        DistroFormatVersion three = new DistroFormatVersion(2, 1);
+        assertFalse(one.equals(three));
+    }
+
+    @Test
+    public void parcelable() {
+        DistroFormatVersion version = new DistroFormatVersion(2, 3);
+
+        Parcel parcel = Parcel.obtain();
+        version.writeToParcel(parcel, 0 /* flags */);
+        parcel.setDataPosition(0);
+
+        DistroFormatVersion newVersion = DistroFormatVersion.CREATOR.createFromParcel(parcel);
+
+        assertEquals(version, newVersion);
+    }
+
+    @Test
+    public void supportsVersion() {
+        DistroFormatVersion deviceVersion = new DistroFormatVersion(2, 2);
+        assertTrue(deviceVersion.supports(deviceVersion));
+
+        DistroFormatVersion sameVersion = new DistroFormatVersion(2, 2);
+        assertTrue(deviceVersion.supports(sameVersion));
+
+        // Minor versions are backwards compatible.
+        DistroFormatVersion sameMajorNewerMinor = new DistroFormatVersion(2, 3);
+        assertTrue(deviceVersion.supports(sameMajorNewerMinor));
+        DistroFormatVersion sameMajorOlderMinor = new DistroFormatVersion(2, 1);
+        assertFalse(deviceVersion.supports(sameMajorOlderMinor));
+
+        // Major versions are not backwards compatible.
+        DistroFormatVersion newerMajor = new DistroFormatVersion(1, 2);
+        assertFalse(deviceVersion.supports(newerMajor));
+        DistroFormatVersion olderMajor = new DistroFormatVersion(3, 2);
+        assertFalse(deviceVersion.supports(olderMajor));
+    }
+
+    private static void assertEqualsContract(DistroFormatVersion one, DistroFormatVersion two) {
+        assertEquals(one, two);
+        assertEquals(one.hashCode(), two.hashCode());
+    }
+}
diff --git a/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
new file mode 100644
index 0000000..2fbc9a1
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezone/DistroRulesVersionTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 android.app.timezone;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link DistroRulesVersion}.
+ */
+// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
+public class DistroRulesVersionTest {
+
+    @Test
+    public void equalsAndHashCode() {
+        DistroRulesVersion one = new DistroRulesVersion("2016a", 2);
+        assertEqualsContract(one, one);
+
+        DistroRulesVersion two = new DistroRulesVersion("2016a", 2);
+        assertEqualsContract(one, two);
+
+        DistroRulesVersion three = new DistroRulesVersion("2016b", 1);
+        assertFalse(one.equals(three));
+    }
+
+    @Test
+    public void parcelable() {
+        DistroRulesVersion version = new DistroRulesVersion("2016a", 2);
+
+        Parcel parcel = Parcel.obtain();
+        version.writeToParcel(parcel, 0 /* flags */);
+        parcel.setDataPosition(0);
+
+        DistroRulesVersion newVersion = DistroRulesVersion.CREATOR.createFromParcel(parcel);
+
+        assertEquals(version, newVersion);
+    }
+
+    @Test
+    public void isOlderThan() {
+        DistroRulesVersion deviceVersion = new DistroRulesVersion("2016b", 2);
+        assertFalse(deviceVersion.isOlderThan(deviceVersion));
+
+        DistroRulesVersion sameVersion = new DistroRulesVersion("2016b", 2);
+        assertFalse(deviceVersion.isOlderThan(sameVersion));
+
+        DistroRulesVersion sameRulesNewerRevision = new DistroRulesVersion("2016b", 3);
+        assertTrue(deviceVersion.isOlderThan(sameRulesNewerRevision));
+
+        DistroRulesVersion sameRulesOlderRevision = new DistroRulesVersion("2016b", 1);
+        assertFalse(deviceVersion.isOlderThan(sameRulesOlderRevision));
+
+        DistroRulesVersion newerRules = new DistroRulesVersion("2016c", 2);
+        assertTrue(deviceVersion.isOlderThan(newerRules));
+
+        DistroRulesVersion olderRules = new DistroRulesVersion("2016a", 2);
+        assertFalse(deviceVersion.isOlderThan(olderRules));
+    }
+
+    private static void assertEqualsContract(DistroRulesVersion one, DistroRulesVersion two) {
+        assertEquals(one, two);
+        assertEquals(one.hashCode(), two.hashCode());
+    }
+}
diff --git a/core/tests/coretests/src/android/app/timezone/RulesStateTest.java b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
new file mode 100644
index 0000000..a9357c9
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezone/RulesStateTest.java
@@ -0,0 +1,187 @@
+/*
+ * 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 android.app.timezone;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.Parcel;
+
+import org.junit.Test;
+
+/**
+ * Tests for {@link RulesState}.
+ */
+// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
+public class RulesStateTest {
+
+    @Test
+    public void equalsAndHashCode() {
+        RulesState one = new RulesState(
+                "2016a", formatVersion(1, 2), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
+                RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
+        assertEqualsContract(one, one);
+
+        RulesState two = new RulesState(
+                "2016a", formatVersion(1, 2), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
+                RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
+        assertEqualsContract(one, two);
+
+        RulesState differentSystemRules = new RulesState(
+                "2016b", formatVersion(1, 2), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
+                RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
+        assertFalse(one.equals(differentSystemRules));
+
+        RulesState differentFormatVersion = new RulesState(
+                "2016a", formatVersion(1, 1), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
+                RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
+        assertFalse(one.equals(differentFormatVersion));
+
+        RulesState differentOperationInProgress = new RulesState(
+                "2016a", formatVersion(1, 1), true /* operationInProgress */,
+                RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */);
+        assertFalse(one.equals(differentOperationInProgress));
+
+        RulesState differentStagedOperation = new RulesState(
+                "2016a", formatVersion(1, 1), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_UNINSTALL, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
+        assertFalse(one.equals(differentStagedOperation));
+
+        RulesState differentStagedInstallVersion = new RulesState(
+                "2016a", formatVersion(1, 1), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 4),
+                RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 2));
+        assertFalse(one.equals(differentStagedInstallVersion));
+
+        RulesState differentInstalled = new RulesState(
+                "2016a", formatVersion(1, 1), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
+                RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
+        assertFalse(one.equals(differentInstalled));
+
+        RulesState differentInstalledVersion = new RulesState(
+                "2016a", formatVersion(1, 1), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016a", 3),
+                RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 3));
+        assertFalse(one.equals(differentInstalledVersion));
+    }
+
+    @Test
+    public void parcelable() {
+        RulesState rulesState1 = new RulesState(
+                "2016a", formatVersion(1, 1), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_INSTALL, rulesVersion("2016b", 2),
+                RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 3));
+        checkParcelableRoundTrip(rulesState1);
+
+        RulesState rulesStateWithNulls = new RulesState(
+                "2016a", formatVersion(1, 1), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
+        checkParcelableRoundTrip(rulesStateWithNulls);
+
+        RulesState rulesStateWithUnknowns = new RulesState(
+                "2016a", formatVersion(1, 1), true /* operationInProgress */,
+                RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */);
+        checkParcelableRoundTrip(rulesStateWithNulls);
+    }
+
+    private static void checkParcelableRoundTrip(RulesState rulesState) {
+        Parcel parcel = Parcel.obtain();
+        rulesState.writeToParcel(parcel, 0 /* flags */);
+        parcel.setDataPosition(0);
+
+        RulesState newVersion = RulesState.CREATOR.createFromParcel(parcel);
+
+        assertEquals(rulesState, newVersion);
+    }
+
+    @Test
+    public void isSystemVersionOlderThan() {
+        RulesState rulesState = new RulesState(
+                "2016b", formatVersion(1, 1), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_INSTALLED, rulesVersion("2016b", 3));
+        assertFalse(rulesState.isSystemVersionOlderThan(rulesVersion("2016a", 1)));
+        assertFalse(rulesState.isSystemVersionOlderThan(rulesVersion("2016b", 1)));
+        assertTrue(rulesState.isSystemVersionOlderThan(rulesVersion("2016c", 1)));
+    }
+
+    @Test
+    public void isInstalledDistroOlderThan() {
+        RulesState operationInProgress = new RulesState(
+                "2016b", formatVersion(1, 1), true /* operationInProgress */,
+                RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
+                RulesState.STAGED_OPERATION_UNKNOWN, null /* installedDistroRulesVersion */);
+        try {
+            operationInProgress.isInstalledDistroOlderThan(rulesVersion("2016b", 1));
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+
+        RulesState nothingInstalled = new RulesState(
+                "2016b", formatVersion(1, 1), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
+        try {
+            nothingInstalled.isInstalledDistroOlderThan(rulesVersion("2016b", 1));
+            fail();
+        } catch (IllegalStateException expected) {
+        }
+
+        DistroRulesVersion installedVersion = rulesVersion("2016b", 3);
+        RulesState rulesStateWithInstalledVersion = new RulesState(
+                "2016b", formatVersion(1, 1), false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_INSTALLED, installedVersion);
+
+        DistroRulesVersion olderRules = rulesVersion("2016a", 1);
+        assertEquals(installedVersion.isOlderThan(olderRules),
+                rulesStateWithInstalledVersion.isInstalledDistroOlderThan(olderRules));
+
+        DistroRulesVersion sameRules = rulesVersion("2016b", 1);
+        assertEquals(installedVersion.isOlderThan(sameRules),
+                rulesStateWithInstalledVersion.isInstalledDistroOlderThan(sameRules));
+
+        DistroRulesVersion newerRules = rulesVersion("2016c", 1);
+        assertEquals(installedVersion.isOlderThan(newerRules),
+                rulesStateWithInstalledVersion.isInstalledDistroOlderThan(newerRules));
+    }
+
+    private static void assertEqualsContract(RulesState one, RulesState two) {
+        assertEquals(one, two);
+        assertEquals(one.hashCode(), two.hashCode());
+    }
+
+    private static DistroRulesVersion rulesVersion(String rulesVersion, int revision) {
+        return new DistroRulesVersion(rulesVersion, revision);
+    }
+
+    private static DistroFormatVersion formatVersion(int majorVersion, int minorVersion) {
+        return new DistroFormatVersion(majorVersion, minorVersion);
+    }
+}
diff --git a/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
new file mode 100644
index 0000000..e7a839c
--- /dev/null
+++ b/core/tests/coretests/src/android/app/timezone/RulesUpdaterContractTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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 android.app.timezone;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.mockito.hamcrest.MockitoHamcrest.argThat;
+
+import android.content.Context;
+import android.content.Intent;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.Test;
+
+/**
+ * Tests for {@link RulesUpdaterContract}.
+ */
+// TODO(nfuller) Move to CTS once this class is part of the SystemApi. http://b/31008728
+public class RulesUpdaterContractTest {
+
+    @Test
+    public void createUpdaterIntent() throws Exception {
+        String packageName = "foobar";
+        Intent intent = RulesUpdaterContract.createUpdaterIntent(packageName);
+
+        assertEquals(RulesUpdaterContract.ACTION_TRIGGER_RULES_UPDATE_CHECK, intent.getAction());
+        assertEquals(packageName, intent.getPackage());
+        assertEquals(Intent.FLAG_INCLUDE_STOPPED_PACKAGES, intent.getFlags());
+    }
+
+    @Test
+    public void sendBroadcast() throws Exception {
+        String packageName = "foobar";
+        byte[] tokenBytes = new byte[] { 1, 2, 3, 4, 5 };
+
+        Intent expectedIntent = RulesUpdaterContract.createUpdaterIntent(packageName);
+        expectedIntent.putExtra(RulesUpdaterContract.EXTRA_CHECK_TOKEN, tokenBytes);
+
+        Context mockContext = mock(Context.class);
+
+        RulesUpdaterContract.sendBroadcast(mockContext, packageName, tokenBytes);
+
+        verify(mockContext).sendBroadcast(
+                filterEquals(expectedIntent),
+                eq(RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION));
+    }
+
+    /**
+     * Registers a mockito parameter matcher that uses {@link Intent#filterEquals(Intent)}. to
+     * check the parameter against the intent supplied.
+     */
+    private static Intent filterEquals(final Intent expected) {
+        final Matcher<Intent> m = new BaseMatcher<Intent>() {
+            @Override
+            public boolean matches(Object actual) {
+                return actual != null && expected.filterEquals((Intent) actual);
+            }
+            @Override
+            public void describeTo(Description description) {
+                description.appendText(expected.toString());
+            }
+        };
+        return argThat(m);
+    }
+}
diff --git a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
index 5e426e8..9c904d1 100644
--- a/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
+++ b/core/tests/coretests/src/android/content/res/FontResourcesParserTest.java
@@ -68,19 +68,19 @@
         assertEquals(4, fileEntries.length);
         FontFileResourceEntry font1 = fileEntries[0];
         assertEquals(400, font1.getWeight());
-        assertEquals(false, font1.isItalic());
+        assertEquals(0, font1.getItalic());
         assertEquals("res/font/samplefont.ttf", font1.getFileName());
         FontFileResourceEntry font2 = fileEntries[1];
         assertEquals(400, font2.getWeight());
-        assertEquals(true, font2.isItalic());
+        assertEquals(1, font2.getItalic());
         assertEquals("res/font/samplefont2.ttf", font2.getFileName());
         FontFileResourceEntry font3 = fileEntries[2];
         assertEquals(800, font3.getWeight());
-        assertEquals(false, font3.isItalic());
+        assertEquals(0, font3.getItalic());
         assertEquals("res/font/samplefont3.ttf", font3.getFileName());
         FontFileResourceEntry font4 = fileEntries[3];
         assertEquals(800, font4.getWeight());
-        assertEquals(true, font4.isItalic());
+        assertEquals(1, font4.getItalic());
         assertEquals("res/font/samplefont4.ttf", font4.getFileName());
     }
 
diff --git a/core/tests/coretests/src/android/os/VintfObjectTest.java b/core/tests/coretests/src/android/os/VintfObjectTest.java
index aaaf55c..821ee80 100644
--- a/core/tests/coretests/src/android/os/VintfObjectTest.java
+++ b/core/tests/coretests/src/android/os/VintfObjectTest.java
@@ -26,5 +26,8 @@
         // From /system/manifest.xml
         assertTrue(String.join("", xmls).contains(
                 "<manifest version=\"1.0\" type=\"framework\">"));
+        // From /system/compatibility-matrix.xml
+        assertTrue(String.join("", xmls).contains(
+                "<compatibility-matrix version=\"1.0\" type=\"framework\">"));
     }
 }
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 8d64aed..ecc04f2 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -110,6 +110,8 @@
                     Settings.Global.BLE_SCAN_ALWAYS_AVAILABLE,
                     Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
+                    Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
+                    Settings.Global.BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX,
                     Settings.Global.BLUETOOTH_DISABLED_PROFILES,
                     Settings.Global.BLUETOOTH_HEADSET_PRIORITY_PREFIX,
                     Settings.Global.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX,
@@ -307,6 +309,7 @@
                     Settings.Global.SETUP_PREPAID_DETECTION_REDIR_HOST,
                     Settings.Global.SETUP_PREPAID_DETECTION_TARGET_URL,
                     Settings.Global.SHORTCUT_MANAGER_CONSTANTS,
+                    Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
                     Settings.Global.SHOW_TEMPERATURE_WARNING,
                     Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
                     Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
@@ -370,6 +373,8 @@
                     Settings.Global.WIFI_REENABLE_DELAY_MS,
                     Settings.Global.WIFI_SAVED_STATE,
                     Settings.Global.WIFI_SCAN_ALWAYS_AVAILABLE,
+                    Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_INTERVAL_MS,
+                    Settings.Global.WIFI_SCAN_BACKGROUND_THROTTLE_PACKAGE_WHITELIST,
                     Settings.Global.WIFI_SCAN_INTERVAL_WHEN_P2P_CONNECTED_MS,
                     Settings.Global.WIFI_SLEEP_POLICY,
                     Settings.Global.WIFI_SUPPLICANT_SCAN_INTERVAL_MS,
@@ -394,8 +399,11 @@
                  Settings.Secure.ANR_SHOW_BACKGROUND,
                  Settings.Secure.ASSISTANT,
                  Settings.Secure.ASSIST_DISCLOSURE_ENABLED,
+                 Settings.Secure.ASSIST_GESTURE_ENABLED_KEYGUARD,
+                 Settings.Secure.ASSIST_GESTURE_ENABLED_SLEEP,
                  Settings.Secure.ASSIST_SCREENSHOT_ENABLED,
                  Settings.Secure.ASSIST_STRUCTURE_ENABLED,
+                 Settings.Secure.AUTOFILL_SERVICE_SEARCH_URI,
                  Settings.Secure.AUTOMATIC_STORAGE_MANAGER_BYTES_CLEARED,
                  Settings.Secure.AUTOMATIC_STORAGE_MANAGER_ENABLED,
                  Settings.Secure.AUTOMATIC_STORAGE_MANAGER_LAST_RUN,
@@ -403,7 +411,6 @@
                  Settings.Secure.BACKUP_ENABLED,
                  Settings.Secure.BACKUP_PROVISIONED,
                  Settings.Secure.BACKUP_TRANSPORT,
-                 Settings.Secure.BLUETOOTH_HCI_LOG,
                  Settings.Secure.CAMERA_LIFT_TRIGGER_ENABLED, // Candidate for backup?
                  Settings.Secure.CARRIER_APPS_HANDLED,
                  Settings.Secure.CMAS_ADDITIONAL_BROADCAST_PKG,
diff --git a/core/tests/coretests/src/android/text/method/BackspaceTest.java b/core/tests/coretests/src/android/text/method/BackspaceTest.java
index 6e41831..8b5cc60 100644
--- a/core/tests/coretests/src/android/text/method/BackspaceTest.java
+++ b/core/tests/coretests/src/android/text/method/BackspaceTest.java
@@ -16,10 +16,13 @@
 
 package android.text.method;
 
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
+import android.util.KeyUtils;
 import android.view.KeyEvent;
+import android.widget.EditText;
 import android.widget.TextView.BufferType;
 import org.junit.Before;
 import org.junit.Test;
@@ -33,13 +36,21 @@
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class BackspaceTest extends KeyListenerTestCase {
+public class BackspaceTest {
+    private EditText mTextView;
+
     private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
         public int getInputType() {
             return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
         }
     };
 
+    @Before
+    public void setup() {
+        mTextView = new EditText(InstrumentationRegistry.getInstrumentation().getContext());
+    }
+
+
     // Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event.
     // Then update the state to the result of TextView.
     private void backspace(final EditorState state, int modifiers) {
@@ -47,7 +58,8 @@
         mTextView.setKeyListener(mKeyListener);
         mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
 
-        final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_DEL, modifiers);
+        final KeyEvent keyEvent = KeyUtils.generateKeyEvent(
+            KeyEvent.KEYCODE_DEL, KeyEvent.ACTION_DOWN, modifiers);
         mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
 
         state.mText = mTextView.getText();
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
index 6914e21..c3a5f80 100644
--- a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
+++ b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
@@ -16,10 +16,13 @@
 
 package android.text.method;
 
+import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.text.InputType;
+import android.util.KeyUtils;
 import android.view.KeyEvent;
+import android.widget.EditText;
 import android.widget.TextView.BufferType;
 
 import org.junit.Before;
@@ -34,13 +37,20 @@
  */
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class ForwardDeleteTest extends KeyListenerTestCase {
+public class ForwardDeleteTest {
+    private EditText mTextView;
+
     private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
         public int getInputType() {
             return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
         }
     };
 
+    @Before
+    public void setup() {
+        mTextView = new EditText(InstrumentationRegistry.getInstrumentation().getContext());
+    }
+
     // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event.
     // Then update the state to the result of TextView.
     private void forwardDelete(final EditorState state, int modifiers) {
@@ -48,7 +58,8 @@
         mTextView.setKeyListener(mKeyListener);
         mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
 
-        final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers);
+        final KeyEvent keyEvent = KeyUtils.generateKeyEvent(
+            KeyEvent.KEYCODE_FORWARD_DEL, KeyEvent.ACTION_DOWN, modifiers);
         mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
 
         state.mText = mTextView.getText();
diff --git a/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java b/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java
deleted file mode 100644
index 99a0091..0000000
--- a/core/tests/coretests/src/android/text/method/KeyListenerTestCase.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.text.method;
-
-import android.app.Instrumentation;
-import android.support.test.InstrumentationRegistry;
-import android.view.KeyEvent;
-import android.widget.EditText;
-
-public abstract class KeyListenerTestCase {
-    protected Instrumentation mInstrumentation;
-    protected EditText mTextView;
-
-    public KeyListenerTestCase() {
-    }
-
-    protected void setup() {
-        mInstrumentation = InstrumentationRegistry.getInstrumentation();
-        mTextView = new EditText(mInstrumentation.getContext());
-    }
-
-    protected static KeyEvent getKey(int keycode, int metaState) {
-        long currentTime = System.currentTimeMillis();
-        return new KeyEvent(currentTime, currentTime, KeyEvent.ACTION_DOWN, keycode,
-                0 /* repeat */, metaState);
-    }
-}
diff --git a/core/tests/coretests/src/android/util/KeyUtils.java b/core/tests/coretests/src/android/util/KeyUtils.java
index b58fda3..593f727 100644
--- a/core/tests/coretests/src/android/util/KeyUtils.java
+++ b/core/tests/coretests/src/android/util/KeyUtils.java
@@ -85,4 +85,19 @@
         }
         inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER));
     }
+
+    /**
+     * Generates a {@link KeyEvent}.
+     *
+     * @param keycode The integer keycode for the event to be generated.
+     * @param keyEventAction The integer {@link KeyEvent} action code.
+     * @param metaState Flags indicating which meta keys are currently pressed.
+     *
+     * @return a new {@link KeyEvent} for current time.
+     */
+    public static KeyEvent generateKeyEvent(int keycode, int keyEventAction, int metaState) {
+        long currentTime = System.currentTimeMillis();
+        return new KeyEvent(currentTime, currentTime, keyEventAction, keycode,
+            0 /* repeat */, metaState);
+    }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 742fd60..7b7031b 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -40,6 +40,7 @@
 public class TextClassificationManagerTest {
 
     private static final LocaleList LOCALES = LocaleList.forLanguageTags("en");
+    private static final String NO_TYPE = null;
 
     private TextClassificationManager mTcm;
     private TextClassifier mClassifier;
@@ -102,6 +103,19 @@
     }
 
     @Test
+    public void testSmartSelection_withEmoji() {
+        if (isTextClassifierDisabled()) return;
+
+        String text = "\uD83D\uDE02 Hello.";
+        String selected = "Hello";
+        int startIndex = text.indexOf(selected);
+        int endIndex = startIndex + selected.length();
+
+        assertThat(mClassifier.suggestSelection(text, startIndex, endIndex, LOCALES),
+                isTextSelection(startIndex, endIndex, NO_TYPE));
+    }
+
+    @Test
     public void testClassifyText() {
         if (isTextClassifierDisabled()) return;
 
@@ -172,12 +186,17 @@
                     TextSelection selection = (TextSelection) o;
                     return startIndex == selection.getSelectionStartIndex()
                             && endIndex == selection.getSelectionEndIndex()
-                            && selection.getEntityCount() > 0
-                            && type.equals(selection.getEntity(0));
+                            && typeMatches(selection, type);
                 }
                 return false;
             }
 
+            private boolean typeMatches(TextSelection selection, String type) {
+                return type == null
+                        || (selection.getEntityCount() > 0
+                                && type.trim().equalsIgnoreCase(selection.getEntity(0)));
+            }
+
             @Override
             public void describeTo(Description description) {
                 description.appendValue(
diff --git a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk
index c70c1d3..5a545e5 100644
--- a/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/ExternalLocAllPermsTestApp/Android.mk
@@ -22,6 +22,8 @@
 
 LOCAL_SDK_VERSION := current
 
+LOCAL_STATIC_JAVA_LIBRARIES := junit
+
 LOCAL_PACKAGE_NAME := ExternalLocAllPermsTestApp
 
 include $(BUILD_PACKAGE)
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
index 7946e1a..b35cbae 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
+++ b/core/tests/hosttests/test-apps/ExternalSharedPerms/Android.mk
@@ -20,6 +20,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+
 LOCAL_SDK_VERSION := current
 
 LOCAL_PACKAGE_NAME := ExternalSharedPermsTestApp
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
index 657d0a4..06812b5 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsBT/Android.mk
@@ -20,6 +20,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+
 LOCAL_SDK_VERSION := current
 
 LOCAL_PACKAGE_NAME := ExternalSharedPermsBTTestApp
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
index d4450dc..48bceaf 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsDiffKey/Android.mk
@@ -20,6 +20,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+
 LOCAL_SDK_VERSION := current
 
 LOCAL_PACKAGE_NAME := ExternalSharedPermsDiffKeyTestApp
diff --git a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
index 8154862..569d102 100644
--- a/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
+++ b/core/tests/hosttests/test-apps/ExternalSharedPermsFL/Android.mk
@@ -20,6 +20,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+
 LOCAL_SDK_VERSION := current
 
 LOCAL_PACKAGE_NAME := ExternalSharedPermsFLTestApp
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index abdab39..8a36120 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -23,6 +23,7 @@
 import android.annotation.Size;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.StrictMode;
 import android.os.Trace;
 import android.util.DisplayMetrics;
 import android.util.Log;
@@ -600,6 +601,13 @@
         src.position(position);
     }
 
+    private void noteHardwareBitmapSlowCall() {
+        if (getConfig() == Config.HARDWARE) {
+            StrictMode.noteSlowCall("Warning: attempt to read pixels from hardware "
+                    + "bitmap, which is very slow operation");
+        }
+    }
+
     /**
      * Tries to make a new bitmap based on the dimensions of this bitmap,
      * setting the new bitmap's config to the one specified, and then copying
@@ -618,6 +626,7 @@
         if (config == Config.HARDWARE && isMutable) {
             throw new IllegalArgumentException("Hardware bitmaps are always immutable");
         }
+        noteHardwareBitmapSlowCall();
         Bitmap b = nativeCopy(mNativePtr, config.nativeInt, isMutable);
         if (b != null) {
             b.setPremultiplied(mRequestPremultiplied);
@@ -635,6 +644,7 @@
      */
     public Bitmap createAshmemBitmap() {
         checkRecycled("Can't copy a recycled bitmap");
+        noteHardwareBitmapSlowCall();
         Bitmap b = nativeCopyAshmem(mNativePtr);
         if (b != null) {
             b.setPremultiplied(mRequestPremultiplied);
@@ -652,6 +662,7 @@
      */
     public Bitmap createAshmemBitmap(Config config) {
         checkRecycled("Can't copy a recycled bitmap");
+        noteHardwareBitmapSlowCall();
         Bitmap b = nativeCopyAshmemConfig(mNativePtr, config.nativeInt);
         if (b != null) {
             b.setPremultiplied(mRequestPremultiplied);
@@ -772,6 +783,7 @@
 
         boolean isHardware = source.getConfig() == Config.HARDWARE;
         if (isHardware) {
+            source.noteHardwareBitmapSlowCall();
             source = nativeCopyPreserveInternalConfig(source.mNativePtr);
         }
 
@@ -1218,6 +1230,7 @@
         if (quality < 0 || quality > 100) {
             throw new IllegalArgumentException("quality must be 0..100");
         }
+        StrictMode.noteSlowCall("Compression of a bitmap is slow");
         Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
         boolean result = nativeCompress(mNativePtr, format.nativeInt,
                 quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
@@ -1792,6 +1805,7 @@
      */
     public void writeToParcel(Parcel p, int flags) {
         checkRecycled("Can't parcel a recycled bitmap");
+        noteHardwareBitmapSlowCall();
         if (!nativeWriteToParcel(mNativePtr, mIsMutable, mDensity, p)) {
             throw new RuntimeException("native writeToParcel failed");
         }
@@ -1838,6 +1852,7 @@
     public Bitmap extractAlpha(Paint paint, int[] offsetXY) {
         checkRecycled("Can't extractAlpha on a recycled bitmap");
         long nativePaint = paint != null ? paint.getNativeInstance() : 0;
+        noteHardwareBitmapSlowCall();
         Bitmap bm = nativeExtractAlpha(mNativePtr, nativePaint, offsetXY);
         if (bm == null) {
             throw new RuntimeException("Failed to extractAlpha on Bitmap");
@@ -1853,6 +1868,8 @@
      */
     public boolean sameAs(Bitmap other) {
         checkRecycled("Can't call sameAs on a recycled bitmap!");
+        noteHardwareBitmapSlowCall();
+        other.noteHardwareBitmapSlowCall();
         if (this == other) return true;
         if (other == null) return false;
         if (other.isRecycled()) {
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index f38d8d2..5a56f53 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -123,7 +123,7 @@
     public static final int BOLD_ITALIC = 3;
 
     private int mStyle = 0;
-    private int mBaseWeight = 0;
+    private int mWeight = 0;
 
     // Value for weight and italic. Indicates the value is resolved by font metadata.
     // Must be the same as the C++ constant in core/jni/android/graphics/FontFamily.cpp
@@ -233,8 +233,7 @@
                 // TODO: Add ttc and variation font support. (b/37853920)
                 if (!fontFamily.addFontFromAssetManager(mgr, fontFile.getFileName(),
                         0 /* resourceCookie */, false /* isAsset */, 0 /* ttcIndex */,
-                        fontFile.getWeight(), fontFile.isItalic() ? STYLE_ITALIC : STYLE_NORMAL,
-                        null /* axes */)) {
+                        fontFile.getWeight(), fontFile.getItalic(), null /* axes */)) {
                     return null;
                 }
             }
@@ -545,7 +544,7 @@
                 return base;
             }
 
-            final int weight = (mWeight == RESOLVE_BY_FONT_TABLE) ? base.mBaseWeight : mWeight;
+            final int weight = (mWeight == RESOLVE_BY_FONT_TABLE) ? base.mWeight : mWeight;
             final boolean italic =
                     (mItalic == RESOLVE_BY_FONT_TABLE) ? (base.mStyle & ITALIC) != 0 : mItalic == 1;
             final int key = weight << 1 | (italic ? 1 : 0);
@@ -883,7 +882,7 @@
 
         native_instance = ni;
         mStyle = nativeGetStyle(ni);
-        mBaseWeight = nativeGetBaseWeight(ni);
+        mWeight = nativeGetWeight(ni);
     }
 
     private static FontFamily makeFamilyFromParsed(FontConfig.Family family,
@@ -1069,7 +1068,7 @@
     private static native long nativeCreateWeightAlias(long native_instance, int weight);
     private static native void nativeUnref(long native_instance);
     private static native int  nativeGetStyle(long native_instance);
-    private static native int  nativeGetBaseWeight(long native_instance);
+    private static native int  nativeGetWeight(long native_instance);
     private static native long nativeCreateFromArray(long[] familyArray, int weight, int italic);
     private static native void nativeSetDefault(long native_instance);
     private static native int[] nativeGetSupportedAxes(long native_instance);
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index bc40191..443aa49 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -188,19 +188,19 @@
 
         // Inset attribute may be overridden by more specific attributes.
         if (a.hasValue(R.styleable.InsetDrawable_inset)) {
-            final InsetValue inset = getInset(a, R.styleable.InsetDrawable_inset, 0);
+            final InsetValue inset = getInset(a, R.styleable.InsetDrawable_inset, new InsetValue());
             state.mInsetLeft = inset;
             state.mInsetTop = inset;
             state.mInsetRight = inset;
             state.mInsetBottom = inset;
         }
-        state.mInsetLeft = getInset(a, R.styleable.InsetDrawable_insetLeft, 0);
-        state.mInsetTop = getInset(a, R.styleable.InsetDrawable_insetTop, 0);
-        state.mInsetRight = getInset(a, R.styleable.InsetDrawable_insetRight, 0);
-        state.mInsetBottom = getInset(a, R.styleable.InsetDrawable_insetBottom, 0);
+        state.mInsetLeft = getInset(a, R.styleable.InsetDrawable_insetLeft, state.mInsetLeft);
+        state.mInsetTop = getInset(a, R.styleable.InsetDrawable_insetTop, state.mInsetTop);
+        state.mInsetRight = getInset(a, R.styleable.InsetDrawable_insetRight, state.mInsetRight);
+        state.mInsetBottom = getInset(a, R.styleable.InsetDrawable_insetBottom, state.mInsetBottom);
     }
 
-    private InsetValue getInset(@NonNull TypedArray a, int index, int defaultValue) {
+    private InsetValue getInset(@NonNull TypedArray a, int index, InsetValue defaultValue) {
         if (a.hasValue(index)) {
             TypedValue tv = a.peekValue(index);
             if (tv.type == TypedValue.TYPE_FRACTION) {
@@ -210,10 +210,13 @@
                 }
                 return new InsetValue(f, 0);
             } else {
-                return new InsetValue(0f, a.getDimensionPixelOffset(index, defaultValue));
+                int dimension = a.getDimensionPixelOffset(index, 0);
+                if (dimension != 0) {
+                    return new InsetValue(0, dimension);
+                }
             }
         }
-        return new InsetValue();
+        return defaultValue;
     }
 
     private void getInsets(Rect out) {
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index ea804d0..3fe730f 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -599,9 +599,9 @@
         private final Context context;
         private final ServiceConnection serviceConnection;
         private final IKeyChainService service;
-        private KeyChainConnection(Context context,
-                                   ServiceConnection serviceConnection,
-                                   IKeyChainService service) {
+        protected KeyChainConnection(Context context,
+                                     ServiceConnection serviceConnection,
+                                     IKeyChainService service) {
             this.context = context;
             this.serviceConnection = serviceConnection;
             this.service = service;
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
deleted file mode 100644
index a740b13..0000000
--- a/keystore/tests/Android.mk
+++ /dev/null
@@ -1,16 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-LOCAL_CERTIFICATE := platform
-
-LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt
-LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_PACKAGE_NAME := KeyStoreTests
-
-include $(BUILD_PACKAGE)
diff --git a/keystore/tests/AndroidManifest.xml b/keystore/tests/AndroidManifest.xml
deleted file mode 100644
index 415442f..0000000
--- a/keystore/tests/AndroidManifest.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2009 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.
--->
-
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-          package="android.security.tests"
-          android:sharedUserId="android.uid.system">
-
-    <application>
-        <uses-library android:name="android.test.runner" />
-    </application>
-
-    <instrumentation android:name="android.test.InstrumentationTestRunner"
-        android:targetPackage="android.security.tests"
-        android:label="KeyStore Tests">
-    </instrumentation>
-</manifest>
diff --git a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java b/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
deleted file mode 100644
index bc8dd13..0000000
--- a/keystore/tests/src/android/security/KeyPairGeneratorSpecTest.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.security;
-
-import android.test.AndroidTestCase;
-
-import java.math.BigInteger;
-import java.util.Date;
-
-import javax.security.auth.x500.X500Principal;
-
-public class KeyPairGeneratorSpecTest extends AndroidTestCase {
-    private static final String TEST_ALIAS_1 = "test1";
-
-    private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
-
-    private static final long NOW_MILLIS = System.currentTimeMillis();
-
-    private static final BigInteger SERIAL_1 = BigInteger.ONE;
-
-    /* We have to round this off because X509v3 doesn't store milliseconds. */
-    private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
-
-    @SuppressWarnings("deprecation")
-    private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
-
-    public void testConstructor_Success() throws Exception {
-        KeyPairGeneratorSpec spec =
-                new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1,
-                        SERIAL_1, NOW, NOW_PLUS_10_YEARS, 0);
-
-        assertEquals("Context should be the one specified", getContext(), spec.getContext());
-
-        assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias());
-
-        assertEquals("Key algorithm should be the one specified", "RSA", spec.getKeyType());
-
-        assertEquals("Key size should be the one specified", 1024, spec.getKeySize());
-
-        assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN());
-
-        assertEquals("startDate should be the one specified", NOW, spec.getStartDate());
-
-        assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
-    }
-
-    public void testBuilder_Success() throws Exception {
-        KeyPairGeneratorSpec spec = new KeyPairGeneratorSpec.Builder(getContext())
-                .setAlias(TEST_ALIAS_1)
-                .setKeyType("RSA")
-                .setKeySize(1024)
-                .setSubject(TEST_DN_1)
-                .setSerialNumber(SERIAL_1)
-                .setStartDate(NOW)
-                .setEndDate(NOW_PLUS_10_YEARS)
-                .setEncryptionRequired()
-                .build();
-
-        assertEquals("Context should be the one specified", getContext(), spec.getContext());
-
-        assertEquals("Alias should be the one specified", TEST_ALIAS_1, spec.getKeystoreAlias());
-
-        assertEquals("Key algorithm should be the one specified", "RSA", spec.getKeyType());
-
-        assertEquals("Key size should be the one specified", 1024, spec.getKeySize());
-
-        assertEquals("subjectDN should be the one specified", TEST_DN_1, spec.getSubjectDN());
-
-        assertEquals("startDate should be the one specified", NOW, spec.getStartDate());
-
-        assertEquals("endDate should be the one specified", NOW_PLUS_10_YEARS, spec.getEndDate());
-
-        assertEquals("encryption flag should be on", KeyStore.FLAG_ENCRYPTED, spec.getFlags());
-    }
-
-    public void testConstructor_NullContext_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(null, TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1, NOW,
-                    NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when context is null");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-
-    public void testConstructor_NullKeystoreAlias_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), null, "RSA", 1024, null, TEST_DN_1, SERIAL_1, NOW,
-                    NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when keystoreAlias is null");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-
-    public void testConstructor_NullSubjectDN_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, null, SERIAL_1, NOW,
-                    NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when subjectDN is null");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-
-    public void testConstructor_NullSerial_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, null, NOW,
-                    NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when startDate is null");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-
-    public void testConstructor_NullStartDate_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
-                    null, NOW_PLUS_10_YEARS, 0);
-            fail("Should throw IllegalArgumentException when startDate is null");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-
-    public void testConstructor_NullEndDate_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
-                    NOW, null, 0);
-            fail("Should throw IllegalArgumentException when keystoreAlias is null");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-
-    public void testConstructor_EndBeforeStart_Failure() throws Exception {
-        try {
-            new KeyPairGeneratorSpec(getContext(), TEST_ALIAS_1, "RSA", 1024, null, TEST_DN_1, SERIAL_1,
-                    NOW_PLUS_10_YEARS, NOW, 0);
-            fail("Should throw IllegalArgumentException when end is before start");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-}
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
deleted file mode 100644
index 319cf32..0000000
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ /dev/null
@@ -1,974 +0,0 @@
-/*
- * Copyright (C) 2009 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 android.security;
-
-import android.app.Activity;
-import android.os.Binder;
-import android.os.IBinder;
-import android.os.Process;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterBlob;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-import android.test.ActivityUnitTestCase;
-import android.test.AssertionFailedError;
-import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.MediumTest;
-import com.android.org.conscrypt.NativeConstants;
-import java.nio.charset.StandardCharsets;
-import java.util.Arrays;
-import java.util.HashSet;
-import java.security.spec.RSAKeyGenParameterSpec;
-
-/**
- * Junit / Instrumentation test case for KeyStore class
- *
- * Running the test suite:
- *
- *  runtest keystore-unit
- *
- * Or this individual test case:
- *
- *  runtest --path frameworks/base/keystore/tests/src/android/security/KeyStoreTest.java
- */
-@MediumTest
-public class KeyStoreTest extends ActivityUnitTestCase<Activity> {
-    private static final String TEST_PASSWD = "12345678";
-    private static final String TEST_PASSWD2 = "87654321";
-    private static final String TEST_KEYNAME = "test-key";
-    private static final String TEST_KEYNAME1 = "test-key.1";
-    private static final String TEST_KEYNAME2 = "test-key\02";
-    private static final byte[] TEST_KEYVALUE = "test value".getBytes(StandardCharsets.UTF_8);
-
-    // "Hello, World" in Chinese
-    private static final String TEST_I18N_KEY = "\u4F60\u597D, \u4E16\u754C";
-    private static final byte[] TEST_I18N_VALUE = TEST_I18N_KEY.getBytes(StandardCharsets.UTF_8);
-
-    // Test vector data for signatures
-    private static final int RSA_KEY_SIZE = 1024;
-    private static final byte[] TEST_DATA =  new byte[RSA_KEY_SIZE / 8];
-    static {
-        for (int i = 0; i < TEST_DATA.length; i++) {
-            TEST_DATA[i] = (byte) i;
-        }
-    }
-
-    private KeyStore mKeyStore = null;
-
-    public KeyStoreTest() {
-        super(Activity.class);
-    }
-
-    private static final byte[] PRIVKEY_BYTES = hexToBytes(
-            "308204BE020100300D06092A864886F70D0101010500048204A8308204A4020100028201" +
-            "0100E0473E8AB8F2284FEB9E742FF9748FA118ED98633C92F52AEB7A2EBE0D3BE60329BE" +
-            "766AD10EB6A515D0D2CFD9BEA7930F0C306537899F7958CD3E85B01F8818524D312584A9" +
-            "4B251E3625B54141EDBFEE198808E1BB97FC7CB49B9EAAAF68E9C98D7D0EDC53BBC0FA00" +
-            "34356D6305FBBCC3C7001405386ABBC873CB0F3EF7425F3D33DF7B315AE036D2A0B66AFD" +
-            "47503B169BF36E3B5162515B715FDA83DEAF2C58AEB9ABFB3097C3CC9DD9DBE5EF296C17" +
-            "6139028E8A671E63056D45F40188D2C4133490845DE52C2534E9C6B2478C07BDAE928823" +
-            "B62D066C7770F9F63F3DBA247F530844747BE7AAA85D853B8BD244ACEC3DE3C89AB46453" +
-            "AB4D24C3AC6902030100010282010037784776A5F17698F5AC960DFB83A1B67564E648BD" +
-            "0597CF8AB8087186F2669C27A9ECBDD480F0197A80D07309E6C6A96F925331E57F8B4AC6" +
-            "F4D45EDA45A23269C09FC428C07A4E6EDF738A15DEC97FABD2F2BB47A14F20EA72FCFE4C" +
-            "36E01ADA77BD137CD8D4DA10BB162E94A4662971F175F985FA188F056CB97EE2816F43AB" +
-            "9D3747612486CDA8C16196C30818A995EC85D38467791267B3BF21F273710A6925862576" +
-            "841C5B6712C12D4BD20A2F3299ADB7C135DA5E9515ABDA76E7CAF2A3BE80551D073B78BF" +
-            "1162C48AD2B7F4743A0238EE4D252F7D5E7E6533CCAE64CCB39360075A2FD1E034EC3AE5" +
-            "CE9C408CCBF0E25E4114021687B3DD4754AE8102818100F541884BC3737B2922D4119EF4" +
-            "5E2DEE2CD4CBB75F45505A157AA5009F99C73A2DF0724AC46024306332EA898177634546" +
-            "5DC6DF1E0A6F140AFF3B7396E6A8994AC5DAA96873472FE37749D14EB3E075E629DBEB35" +
-            "83338A6F3649D0A2654A7A42FD9AB6BFA4AC4D481D390BB229B064BDC311CC1BE1B63189" +
-            "DA7C40CDECF2B102818100EA1A742DDB881CEDB7288C87E38D868DD7A409D15A43F445D5" +
-            "377A0B5731DDBFCA2DAF28A8E13CD5C0AFCEC3347D74A39E235A3CD9633F274DE2B94F92" +
-            "DF43833911D9E9F1CF58F27DE2E08FF45964C720D3EC2139DC7CAFC912953CDECB2F355A" +
-            "2E2C35A50FAD754CB3B23166424BA3B6E3112A2B898C38C5C15EDB238693390281805182" +
-            "8F1EC6FD996029901BAF1D7E337BA5F0AF27E984EAD895ACE62BD7DF4EE45A224089F2CC" +
-            "151AF3CD173FCE0474BCB04F386A2CDCC0E0036BA2419F54579262D47100BE931984A3EF" +
-            "A05BECF141574DC079B3A95C4A83E6C43F3214D6DF32D512DE198085E531E616B83FD7DD" +
-            "9D1F4E2607C3333D07C55D107D1D3893587102818100DB4FB50F50DE8EDB53FF34C80931" +
-            "88A0512867DA2CCA04897759E587C244010DAF8664D59E8083D16C164789301F67A9F078" +
-            "060D834A2ADBD367575B68A8A842C2B02A89B3F31FCCEC8A22FE395795C5C6C7422B4E5D" +
-            "74A1E9A8F30E7759B9FC2D639C1F15673E84E93A5EF1506F4315383C38D45CBD1B14048F" +
-            "4721DC82326102818100D8114593AF415FB612DBF1923710D54D07486205A76A3B431949" +
-            "68C0DFF1F11EF0F61A4A337D5FD3741BBC9640E447B8B6B6C47C3AC1204357D3B0C55BA9" +
-            "286BDA73F629296F5FA9146D8976357D3C751E75148696A40B74685C82CE30902D639D72" +
-            "4FF24D5E2E9407EE34EDED2E3B4DF65AA9BCFEB6DF28D07BA6903F165768");
-
-    private static final byte[] AES256_BYTES = hexToBytes(
-            "0CC175B9C0F1B6A831C399E269772661CEC520EA51EA0A47E87295FA3245A605");
-
-    private static byte[] hexToBytes(String s) {
-        int len = s.length();
-        byte[] data = new byte[len / 2];
-        for (int i = 0; i < len; i += 2) {
-            data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(
-                    s.charAt(i + 1), 16));
-        }
-        return data;
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        mKeyStore = KeyStore.getInstance();
-        if (mKeyStore.state() != KeyStore.State.UNINITIALIZED) {
-            mKeyStore.reset();
-        }
-        assertEquals("KeyStore should be in an uninitialized state",
-                KeyStore.State.UNINITIALIZED, mKeyStore.state());
-        super.setUp();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        mKeyStore.reset();
-        super.tearDown();
-    }
-
-    public void testState() throws Exception {
-        assertEquals(KeyStore.State.UNINITIALIZED, mKeyStore.state());
-    }
-
-    public void testPassword() throws Exception {
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-        assertEquals(KeyStore.State.UNLOCKED, mKeyStore.state());
-    }
-
-    public void testGet() throws Exception {
-        assertNull(mKeyStore.get(TEST_KEYNAME));
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        assertNull(mKeyStore.get(TEST_KEYNAME));
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
-                KeyStore.FLAG_ENCRYPTED));
-        assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
-    }
-
-    public void testPut() throws Exception {
-        assertNull(mKeyStore.get(TEST_KEYNAME));
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
-                KeyStore.FLAG_ENCRYPTED));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
-                KeyStore.FLAG_ENCRYPTED));
-        assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
-    }
-
-    public void testPut_grantedUid_Wifi() throws Exception {
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
-                KeyStore.FLAG_ENCRYPTED));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
-                KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-    }
-
-    public void testPut_ungrantedUid_Bluetooth() throws Exception {
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
-                KeyStore.FLAG_ENCRYPTED));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
-                KeyStore.FLAG_ENCRYPTED));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-    }
-
-    public void testI18n() throws Exception {
-        assertFalse(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE, KeyStore.UID_SELF,
-                KeyStore.FLAG_ENCRYPTED));
-        assertFalse(mKeyStore.contains(TEST_I18N_KEY));
-        mKeyStore.onUserPasswordChanged(TEST_I18N_KEY);
-        assertTrue(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE, KeyStore.UID_SELF,
-                KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mKeyStore.contains(TEST_I18N_KEY));
-    }
-
-    public void testDelete() throws Exception {
-        assertFalse(mKeyStore.delete(TEST_KEYNAME));
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        assertFalse(mKeyStore.delete(TEST_KEYNAME));
-
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
-                KeyStore.FLAG_ENCRYPTED));
-        assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
-        assertTrue(mKeyStore.delete(TEST_KEYNAME));
-        assertNull(mKeyStore.get(TEST_KEYNAME));
-    }
-
-    public void testDelete_grantedUid_Wifi() throws Exception {
-        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
-
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
-                KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-        assertTrue(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-    }
-
-    public void testDelete_ungrantedUid_Bluetooth() throws Exception {
-        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
-
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
-                KeyStore.FLAG_ENCRYPTED));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-        assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-    }
-
-    public void testContains() throws Exception {
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
-                KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-    }
-
-    public void testContains_grantedUid_Wifi() throws Exception {
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID,
-                KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-    }
-
-    public void testContains_grantedUid_Bluetooth() throws Exception {
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-
-        assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID,
-                KeyStore.FLAG_ENCRYPTED));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-    }
-
-    public void testList() throws Exception {
-        String[] emptyResult = mKeyStore.list(TEST_KEYNAME);
-        assertNotNull(emptyResult);
-        assertEquals(0, emptyResult.length);
-
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
-        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
-
-        String[] results = mKeyStore.list(TEST_KEYNAME);
-        assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
-                                               TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
-                     new HashSet(Arrays.asList(results)));
-    }
-
-    public void testList_ungrantedUid_Bluetooth() throws Exception {
-        String[] results1 = mKeyStore.list(TEST_KEYNAME, Process.BLUETOOTH_UID);
-        assertEquals(0, results1.length);
-
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
-        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
-
-        String[] results2 = mKeyStore.list(TEST_KEYNAME, Process.BLUETOOTH_UID);
-        assertEquals(0, results2.length);
-    }
-
-    public void testList_grantedUid_Wifi() throws Exception {
-        String[] results1 = mKeyStore.list(TEST_KEYNAME, Process.WIFI_UID);
-        assertNotNull(results1);
-        assertEquals(0, results1.length);
-
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED);
-        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED);
-
-        String[] results2 = mKeyStore.list(TEST_KEYNAME, Process.WIFI_UID);
-        assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
-                                               TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
-                     new HashSet(Arrays.asList(results2)));
-    }
-
-    public void testList_grantedUid_Vpn() throws Exception {
-        String[] results1 = mKeyStore.list(TEST_KEYNAME, Process.VPN_UID);
-        assertNotNull(results1);
-        assertEquals(0, results1.length);
-
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.VPN_UID, KeyStore.FLAG_ENCRYPTED);
-        mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.VPN_UID, KeyStore.FLAG_ENCRYPTED);
-
-        String[] results2 = mKeyStore.list(TEST_KEYNAME, Process.VPN_UID);
-        assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
-                                               TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
-                     new HashSet(Arrays.asList(results2)));
-    }
-
-    public void testLock() throws Exception {
-        assertFalse(mKeyStore.lock());
-
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        assertEquals(KeyStore.State.UNLOCKED, mKeyStore.state());
-
-        assertTrue(mKeyStore.lock());
-        assertEquals(KeyStore.State.LOCKED, mKeyStore.state());
-    }
-
-    public void testUnlock() throws Exception {
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        assertEquals(KeyStore.State.UNLOCKED, mKeyStore.state());
-        mKeyStore.lock();
-
-        assertFalse(mKeyStore.unlock(TEST_PASSWD2));
-        assertTrue(mKeyStore.unlock(TEST_PASSWD));
-    }
-
-    public void testIsEmpty() throws Exception {
-        assertTrue(mKeyStore.isEmpty());
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        assertTrue(mKeyStore.isEmpty());
-        mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED);
-        assertFalse(mKeyStore.isEmpty());
-        mKeyStore.reset();
-        assertTrue(mKeyStore.isEmpty());
-    }
-
-    public void testGenerate_NotInitialized_Fail() throws Exception {
-        assertFalse("Should fail when keystore is not initialized",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                        RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-    }
-
-    public void testGenerate_Locked_Fail() throws Exception {
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        mKeyStore.lock();
-        assertFalse("Should fail when keystore is locked",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                        RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-    }
-
-    public void testGenerate_Success() throws Exception {
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to generate key when unlocked",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                        RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-    }
-
-    public void testGenerate_grantedUid_Wifi_Success() throws Exception {
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to generate key when unlocked",
-                mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID, NativeConstants.EVP_PKEY_RSA,
-                        RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-    }
-
-    public void testGenerate_ungrantedUid_Bluetooth_Failure() throws Exception {
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID,
-                    NativeConstants.EVP_PKEY_RSA, RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-    }
-
-    public void testImport_Success() throws Exception {
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
-                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-    }
-
-    public void testImport_grantedUid_Wifi_Success() throws Exception {
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
-                PRIVKEY_BYTES, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-    }
-
-    public void testImport_ungrantedUid_Bluetooth_Failure() throws Exception {
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertFalse(mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.BLUETOOTH_UID,
-                KeyStore.FLAG_ENCRYPTED));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-    }
-
-    public void testImport_Failure_BadEncoding() throws Exception {
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-
-        assertFalse("Invalid DER-encoded key should not be imported", mKeyStore.importKey(
-                TEST_KEYNAME, TEST_DATA, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-    }
-
-    public void testSign_Success() throws Exception {
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-
-        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                    RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
-
-        assertNotNull("Signature should not be null", signature);
-    }
-
-    public void testVerify_Success() throws Exception {
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-
-        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                    RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
-
-        assertNotNull("Signature should not be null", signature);
-
-        assertTrue("Signature should verify with same data",
-                mKeyStore.verify(TEST_KEYNAME, TEST_DATA, signature));
-    }
-
-    public void testSign_NotInitialized_Failure() throws Exception {
-        assertNull("Should not be able to sign without first initializing the keystore",
-                mKeyStore.sign(TEST_KEYNAME, TEST_DATA));
-    }
-
-    public void testSign_NotGenerated_Failure() throws Exception {
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-
-        assertNull("Should not be able to sign without first generating keys",
-                mKeyStore.sign(TEST_KEYNAME, TEST_DATA));
-    }
-
-    public void testGrant_Generated_Success() throws Exception {
-        assertTrue("Password should work for keystore",
-                mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                        RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-
-        assertTrue("Should be able to grant key to other user",
-                mKeyStore.grant(TEST_KEYNAME, 0));
-    }
-
-    public void testGrant_Imported_Success() throws Exception {
-        assertTrue("Password should work for keystore", mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to import key for testcase", mKeyStore.importKey(TEST_KEYNAME,
-                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertTrue("Should be able to grant key to other user", mKeyStore.grant(TEST_KEYNAME, 0));
-    }
-
-    public void testGrant_NoKey_Failure() throws Exception {
-        assertTrue("Should be able to unlock keystore for test",
-                mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertFalse("Should not be able to grant without first initializing the keystore",
-                mKeyStore.grant(TEST_KEYNAME, 0));
-    }
-
-    public void testGrant_NotInitialized_Failure() throws Exception {
-        assertFalse("Should not be able to grant without first initializing the keystore",
-                mKeyStore.grant(TEST_KEYNAME, 0));
-    }
-
-    public void testUngrant_Generated_Success() throws Exception {
-        assertTrue("Password should work for keystore",
-                mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                        RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-
-        assertTrue("Should be able to grant key to other user",
-                mKeyStore.grant(TEST_KEYNAME, 0));
-
-        assertTrue("Should be able to ungrant key to other user",
-                mKeyStore.ungrant(TEST_KEYNAME, 0));
-    }
-
-    public void testUngrant_Imported_Success() throws Exception {
-        assertTrue("Password should work for keystore",
-                mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to import key for testcase", mKeyStore.importKey(TEST_KEYNAME,
-                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertTrue("Should be able to grant key to other user",
-                mKeyStore.grant(TEST_KEYNAME, 0));
-
-        assertTrue("Should be able to ungrant key to other user",
-                mKeyStore.ungrant(TEST_KEYNAME, 0));
-    }
-
-    public void testUngrant_NotInitialized_Failure() throws Exception {
-        assertFalse("Should fail to ungrant key when keystore not initialized",
-                mKeyStore.ungrant(TEST_KEYNAME, 0));
-    }
-
-    public void testUngrant_NoGrant_Failure() throws Exception {
-        assertTrue("Password should work for keystore",
-                mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                        RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-
-        assertFalse("Should not be able to revoke not existent grant",
-                mKeyStore.ungrant(TEST_KEYNAME, 0));
-    }
-
-    public void testUngrant_DoubleUngrant_Failure() throws Exception {
-        assertTrue("Password should work for keystore",
-                mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                        RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-
-        assertTrue("Should be able to grant key to other user",
-                mKeyStore.grant(TEST_KEYNAME, 0));
-
-        assertTrue("Should be able to ungrant key to other user",
-                mKeyStore.ungrant(TEST_KEYNAME, 0));
-
-        assertFalse("Should fail to ungrant key to other user second time",
-                mKeyStore.ungrant(TEST_KEYNAME, 0));
-    }
-
-    public void testUngrant_DoubleGrantUngrant_Failure() throws Exception {
-        assertTrue("Password should work for keystore",
-                mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to generate key for testcase",
-                mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                        RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-
-        assertTrue("Should be able to grant key to other user",
-                mKeyStore.grant(TEST_KEYNAME, 0));
-
-        assertTrue("Should be able to grant key to other user a second time",
-                mKeyStore.grant(TEST_KEYNAME, 0));
-
-        assertTrue("Should be able to ungrant key to other user",
-                mKeyStore.ungrant(TEST_KEYNAME, 0));
-
-        assertFalse("Should fail to ungrant key to other user second time",
-                mKeyStore.ungrant(TEST_KEYNAME, 0));
-    }
-
-    public void testDuplicate_grantedUid_Wifi_Success() throws Exception {
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-
-        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                    RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-
-        // source doesn't exist
-        assertFalse(mKeyStore.duplicate(TEST_KEYNAME1, -1, TEST_KEYNAME1, Process.WIFI_UID));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID));
-
-        // Copy from current UID to granted UID
-        assertTrue(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME1, Process.WIFI_UID));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME1));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID));
-        assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME1, Process.WIFI_UID));
-
-        // Copy from granted UID to same granted UID
-        assertTrue(mKeyStore.duplicate(TEST_KEYNAME1, Process.WIFI_UID, TEST_KEYNAME2,
-                Process.WIFI_UID));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME1, Process.WIFI_UID));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME2, Process.WIFI_UID));
-        assertFalse(mKeyStore.duplicate(TEST_KEYNAME1, Process.WIFI_UID, TEST_KEYNAME2,
-                Process.WIFI_UID));
-
-        assertTrue(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, -1));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME1));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME2));
-        assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, -1));
-    }
-
-    public void testDuplicate_ungrantedUid_Bluetooth_Failure() throws Exception {
-        assertTrue(mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-
-        assertTrue(mKeyStore.generate(TEST_KEYNAME, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA,
-                    RSA_KEY_SIZE, KeyStore.FLAG_ENCRYPTED, null));
-
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-
-        assertFalse(mKeyStore.duplicate(TEST_KEYNAME, -1, TEST_KEYNAME2, Process.BLUETOOTH_UID));
-        assertFalse(mKeyStore.duplicate(TEST_KEYNAME, Process.BLUETOOTH_UID, TEST_KEYNAME2,
-                Process.BLUETOOTH_UID));
-
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
-    }
-
-    /**
-     * The amount of time to allow before and after expected time for variance
-     * in timing tests.
-     */
-    private static final long SLOP_TIME_MILLIS = 15000L;
-
-    public void testGetmtime_Success() throws Exception {
-        assertTrue("Password should work for keystore",
-                mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
-                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        long now = System.currentTimeMillis();
-        long actual = mKeyStore.getmtime(TEST_KEYNAME);
-
-        long expectedAfter = now - SLOP_TIME_MILLIS;
-        long expectedBefore = now + SLOP_TIME_MILLIS;
-
-        assertLessThan("Time should be close to current time", expectedBefore, actual);
-        assertGreaterThan("Time should be close to current time", expectedAfter, actual);
-    }
-
-    private static void assertLessThan(String explanation, long expectedBefore, long actual) {
-        if (actual >= expectedBefore) {
-            throw new AssertionFailedError(explanation + ": actual=" + actual
-                    + ", expected before: " + expectedBefore);
-        }
-    }
-
-    private static void assertGreaterThan(String explanation, long expectedAfter, long actual) {
-        if (actual <= expectedAfter) {
-            throw new AssertionFailedError(explanation + ": actual=" + actual
-                    + ", expected after: " + expectedAfter);
-        }
-    }
-
-    public void testGetmtime_NonExist_Failure() throws Exception {
-        assertTrue("Password should work for keystore",
-                mKeyStore.onUserPasswordChanged(TEST_PASSWD));
-
-        assertTrue("Should be able to import key when unlocked", mKeyStore.importKey(TEST_KEYNAME,
-                PRIVKEY_BYTES, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertEquals("-1 should be returned for non-existent key",
-                -1L, mKeyStore.getmtime(TEST_KEYNAME2));
-    }
-
-    private KeyCharacteristics generateRsaKey(String name) throws Exception {
-        KeymasterArguments args = new KeymasterArguments();
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
-        args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-        args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
-        args.addUnsignedLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, RSAKeyGenParameterSpec.F4);
-
-        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
-        int result = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
-        assertEquals("generateRsaKey should succeed", KeyStore.NO_ERROR, result);
-        return outCharacteristics;
-    }
-
-    public void testGenerateKey() throws Exception {
-        generateRsaKey("test");
-        mKeyStore.delete("test");
-    }
-
-    public void testGenerateRsaWithEntropy() throws Exception {
-        byte[] entropy = new byte[] {1,2,3,4,5};
-        String name = "test";
-        KeymasterArguments args = new KeymasterArguments();
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
-        args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-        args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
-        args.addUnsignedLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, RSAKeyGenParameterSpec.F4);
-
-        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
-        int result = mKeyStore.generateKey(name, args, entropy, 0, outCharacteristics);
-        assertEquals("generateKey should succeed", KeyStore.NO_ERROR, result);
-    }
-
-    public void testGenerateAndDelete() throws Exception {
-        generateRsaKey("test");
-        assertTrue("delete should succeed", mKeyStore.delete("test"));
-    }
-
-    public void testGetKeyCharacteristicsSuccess() throws Exception {
-        mKeyStore.onUserPasswordChanged(TEST_PASSWD);
-        String name = "test";
-        KeyCharacteristics gen = generateRsaKey(name);
-        KeyCharacteristics call = new KeyCharacteristics();
-        int result = mKeyStore.getKeyCharacteristics(name, null, null, call);
-        assertEquals("getKeyCharacteristics should succeed", KeyStore.NO_ERROR, result);
-        mKeyStore.delete("test");
-    }
-
-    public void testAppId() throws Exception {
-        String name = "test";
-        byte[] id = new byte[] {0x01, 0x02, 0x03};
-        KeymasterArguments args = new KeymasterArguments();
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
-        args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 2048);
-        args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
-        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-        args.addBytes(KeymasterDefs.KM_TAG_APPLICATION_ID, id);
-        args.addUnsignedLong(KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, RSAKeyGenParameterSpec.F4);
-
-        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
-        int result = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
-        assertEquals("generateRsaKey should succeed", KeyStore.NO_ERROR, result);
-        assertEquals("getKeyCharacteristics should fail without application ID",
-                KeymasterDefs.KM_ERROR_INVALID_KEY_BLOB,
-                mKeyStore.getKeyCharacteristics(name, null, null, outCharacteristics));
-        assertEquals("getKeyCharacteristics should succeed with application ID",
-                KeyStore.NO_ERROR,
-                mKeyStore.getKeyCharacteristics(name, new KeymasterBlob(id), null,
-                    outCharacteristics));
-    }
-
-
-    public void testExportRsa() throws Exception {
-        String name = "test";
-        generateRsaKey(name);
-        ExportResult result = mKeyStore.exportKey(name, KeymasterDefs.KM_KEY_FORMAT_X509, null,
-                null);
-        assertEquals("Export success", KeyStore.NO_ERROR, result.resultCode);
-        // TODO: Verify we have an RSA public key that's well formed.
-    }
-
-    public void testAesGcmEncryptSuccess() throws Exception {
-        String name = "test";
-        KeymasterArguments args = new KeymasterArguments();
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
-        args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
-        args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
-        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-
-        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
-        int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
-        assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc);
-
-        args = new KeymasterArguments();
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
-        args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
-        args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        args.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, 128);
-        OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
-                true, args, null);
-        IBinder token = result.token;
-        assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
-        result = mKeyStore.update(token, null, new byte[] {0x01, 0x02, 0x03, 0x04});
-        assertEquals("Update should succeed", KeyStore.NO_ERROR, result.resultCode);
-        assertEquals("Finish should succeed", KeyStore.NO_ERROR,
-                mKeyStore.finish(token, null, null).resultCode);
-        // TODO: Assert that an AEAD tag was returned by finish
-    }
-
-    public void testBadToken() throws Exception {
-        IBinder token = new Binder();
-        OperationResult result = mKeyStore.update(token, null, new byte[] {0x01});
-        assertEquals("Update with invalid token should fail",
-                KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, result.resultCode);
-    }
-
-    private int importAesKey(String name, byte[] key, int size, int mode) {
-        KeymasterArguments args = new KeymasterArguments();
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
-        args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mode);
-        args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, size);
-        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-        return mKeyStore.importKey(name, args, KeymasterDefs.KM_KEY_FORMAT_RAW, key, 0,
-                new KeyCharacteristics());
-    }
-    private byte[] doOperation(String name, int purpose, byte[] in, KeymasterArguments beginArgs) {
-        OperationResult result = mKeyStore.begin(name, purpose,
-                true, beginArgs, null);
-        assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
-        IBinder token = result.token;
-        result = mKeyStore.update(token, null, in);
-        assertEquals("Update should succeed", KeyStore.NO_ERROR, result.resultCode);
-        assertEquals("All data should be consumed", in.length, result.inputConsumed);
-        assertEquals("Finish should succeed", KeyStore.NO_ERROR,
-                mKeyStore.finish(token, null, null).resultCode);
-        return result.output;
-    }
-
-    public void testImportAes() throws Exception {
-        int result = importAesKey("aes", AES256_BYTES, 256, KeymasterDefs.KM_MODE_ECB);
-        assertEquals("import should succeed", KeyStore.NO_ERROR, result);
-        mKeyStore.delete("aes");
-    }
-
-    public void testAes256Ecb() throws Exception {
-        byte[] key =
-                hexToBytes("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4");
-        String name = "aes";
-        assertEquals(KeyStore.NO_ERROR, importAesKey(name, key, 256, KeymasterDefs.KM_MODE_ECB));
-        byte[][] testVectors = new byte[][] {
-            hexToBytes("6bc1bee22e409f96e93d7e117393172a"),
-            hexToBytes("ae2d8a571e03ac9c9eb76fac45af8e51"),
-            hexToBytes("30c81c46a35ce411e5fbc1191a0a52ef"),
-            hexToBytes("f69f2445df4f9b17ad2b417be66c3710")};
-        byte[][] cipherVectors = new byte[][] {
-            hexToBytes("f3eed1bdb5d2a03c064b5a7e3db181f8"),
-            hexToBytes("591ccb10d410ed26dc5ba74a31362870"),
-            hexToBytes("b6ed21b99ca6f4f9f153e7b1beafed1d"),
-            hexToBytes("23304b7a39f9f3ff067d8d8f9e24ecc7")};
-        KeymasterArguments beginArgs = new KeymasterArguments();
-        beginArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
-        beginArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
-        beginArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        for (int i = 0; i < testVectors.length; i++) {
-            byte[] cipherText = doOperation(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, testVectors[i],
-                    beginArgs);
-            MoreAsserts.assertEquals(cipherVectors[i], cipherText);
-        }
-        for (int i = 0; i < testVectors.length; i++) {
-            byte[] plainText = doOperation(name, KeymasterDefs.KM_PURPOSE_DECRYPT,
-                    cipherVectors[i], beginArgs);
-            MoreAsserts.assertEquals(testVectors[i], plainText);
-        }
-    }
-
-    // This is a very implementation specific test and should be thrown out eventually, however it
-    // is nice for now to test that keystore is properly pruning operations.
-    public void testOperationPruning() throws Exception {
-        String name = "test";
-        KeymasterArguments args = new KeymasterArguments();
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
-        args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
-        args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
-        args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
-
-        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
-        int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
-        assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc);
-
-        args = new KeymasterArguments();
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
-        args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
-        args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
-        OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
-                true, args, null);
-        assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
-        IBinder first = result.token;
-        // Implementation detail: softkeymaster supports 16 concurrent operations
-        for (int i = 0; i < 16; i++) {
-            result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT, true, args, null);
-            assertEquals("Begin should succeed", KeyStore.NO_ERROR, result.resultCode);
-        }
-        // At this point the first operation should be pruned.
-        assertEquals("Operation should be pruned", KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE,
-                mKeyStore.update(first, null, new byte[] {0x01}).resultCode);
-    }
-
-    public void testAuthNeeded() throws Exception {
-        String name = "test";
-        KeymasterArguments args = new KeymasterArguments();
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
-        args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
-        args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_PKCS7);
-        args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, 256);
-        args.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
-        args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 1);
-
-        KeyCharacteristics outCharacteristics = new KeyCharacteristics();
-        int rc = mKeyStore.generateKey(name, args, null, 0, outCharacteristics);
-        assertEquals("Generate should succeed", KeyStore.NO_ERROR, rc);
-        OperationResult result = mKeyStore.begin(name, KeymasterDefs.KM_PURPOSE_ENCRYPT,
-                true, args, null);
-        assertEquals("Begin should expect authorization", KeyStore.OP_AUTH_NEEDED,
-                result.resultCode);
-        IBinder token = result.token;
-        result = mKeyStore.update(token, null, new byte[] {0x01, 0x02, 0x03, 0x04});
-        assertEquals("Update should require authorization",
-                KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED, result.resultCode);
-    }
-
-    public void testPasswordRemovalEncryptedEntry() throws Exception {
-        mKeyStore.onUserPasswordChanged("test");
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
-                KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
-        mKeyStore.onUserPasswordChanged("");
-        // Removing the password should have deleted all entries using FLAG_ENCRYPTED
-        assertNull(mKeyStore.get(TEST_KEYNAME));
-        assertFalse(mKeyStore.contains(TEST_KEYNAME));
-    }
-
-    public void testPasswordRemovalUnencryptedEntry() throws Exception {
-        mKeyStore.onUserPasswordChanged("test");
-        assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, KeyStore.UID_SELF,
-                KeyStore.FLAG_NONE));
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
-        mKeyStore.onUserPasswordChanged("");
-        // Removing the password should not delete unencrypted entries.
-        assertTrue(mKeyStore.contains(TEST_KEYNAME));
-        assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
-    }
-}
diff --git a/keystore/tests/src/android/security/SystemKeyStoreTest.java b/keystore/tests/src/android/security/SystemKeyStoreTest.java
deleted file mode 100644
index ecf7cbc..0000000
--- a/keystore/tests/src/android/security/SystemKeyStoreTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Copyright (C) 2010 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 android.security;
-
-import android.app.Activity;
-import android.security.SystemKeyStore;
-import android.test.ActivityUnitTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-/**
- * Junit / Instrumentation test case for KeyStore class
- *
- * Running the test suite:
- *
- *  runtest keystore-unit
- *
- * Or this individual test case:
- *
- *  runtest --path frameworks/base/keystore/tests/src/android/security/SystemKeyStoreTest.java
- */
-@MediumTest
-public class SystemKeyStoreTest extends ActivityUnitTestCase<Activity> {
-
-    private static final String keyName = "TestKey";
-    private static final String keyName2 = "TestKey2";
-    private SystemKeyStore mSysKeyStore = null;
-
-    public SystemKeyStoreTest() {
-        super(Activity.class);
-    }
-
-    @Override
-    protected void setUp() throws Exception {
-        mSysKeyStore = SystemKeyStore.getInstance();
-        try {
-            mSysKeyStore.deleteKey(keyName);
-            mSysKeyStore.deleteKey(keyName2);
-        } catch (Exception e) { }
-        super.setUp();
-    }
-
-    @Override
-    protected void tearDown() throws Exception {
-        try {
-            mSysKeyStore.deleteKey(keyName);
-            mSysKeyStore.deleteKey(keyName2);
-        } catch (Exception e) { }
-        super.tearDown();
-    }
-
-    public void testBasicAccess() throws Exception {
-        try {
-            byte[] newKey = mSysKeyStore.generateNewKey(128, "AES", keyName);
-            assertNotNull(newKey);
-            byte[] recKey = mSysKeyStore.retrieveKey(keyName);
-            assertEquals(newKey.length, recKey.length);
-            for (int i = 0; i < newKey.length; i++) {
-                assertEquals(newKey[i], recKey[i]);
-            }
-            mSysKeyStore.deleteKey(keyName);
-            byte[] nullKey = mSysKeyStore.retrieveKey(keyName);
-            assertNull(nullKey);
-
-            String newKeyStr = mSysKeyStore.generateNewKeyHexString(128, "AES", keyName2);
-            assertNotNull(newKeyStr);
-            String recKeyStr = mSysKeyStore.retrieveKeyHexString(keyName2);
-            assertEquals(newKeyStr, recKeyStr);
-
-            mSysKeyStore.deleteKey(keyName2);
-            String nullKey2 = mSysKeyStore.retrieveKeyHexString(keyName2);
-            assertNull(nullKey2);
-        } catch (Exception e) {
-            fail();
-        }
-    }
-}
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
deleted file mode 100644
index 1af0b7d..0000000
--- a/keystore/tests/src/android/security/keystore/AndroidKeyPairGeneratorTest.java
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.security.keystore;
-
-import android.security.Credentials;
-import android.security.KeyPairGeneratorSpec;
-import android.security.KeyStore;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeymasterDefs;
-import android.test.AndroidTestCase;
-
-import java.io.ByteArrayInputStream;
-import java.math.BigInteger;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.ECKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.RSAKeyGenParameterSpec;
-import java.text.SimpleDateFormat;
-import java.util.Arrays;
-import java.util.Date;
-
-import javax.security.auth.x500.X500Principal;
-
-public class AndroidKeyPairGeneratorTest extends AndroidTestCase {
-    private android.security.KeyStore mAndroidKeyStore;
-
-    private java.security.KeyPairGenerator mGenerator;
-
-    private static final String TEST_ALIAS_1 = "test1";
-
-    private static final String TEST_ALIAS_2 = "test2";
-
-    private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
-
-    private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2");
-
-    private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE;
-
-    private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L);
-
-    private static final long NOW_MILLIS = System.currentTimeMillis();
-
-    /* We have to round this off because X509v3 doesn't store milliseconds. */
-    private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
-
-    @SuppressWarnings("deprecation")
-    private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
-
-    @Override
-    protected void setUp() throws Exception {
-        mAndroidKeyStore = android.security.KeyStore.getInstance();
-
-        assertTrue(mAndroidKeyStore.reset());
-
-        assertFalse(mAndroidKeyStore.isUnlocked());
-
-        mGenerator = java.security.KeyPairGenerator.getInstance("RSA", "AndroidKeyStore");
-    }
-
-    private void setupPassword() {
-        assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111"));
-        assertTrue(mAndroidKeyStore.isUnlocked());
-
-        String[] aliases = mAndroidKeyStore.list("");
-        assertNotNull(aliases);
-        assertEquals(0, aliases.length);
-    }
-
-    public void testKeyPairGenerator_Initialize_Params_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                .setAlias(TEST_ALIAS_1)
-                .setSubject(TEST_DN_1)
-                .setSerialNumber(TEST_SERIAL_1)
-                .setStartDate(NOW)
-                .setEndDate(NOW_PLUS_10_YEARS)
-                .setEncryptionRequired()
-                .build());
-    }
-
-    public void testKeyPairGenerator_Initialize_KeySize_Encrypted_Failure() throws Exception {
-        setupPassword();
-
-        try {
-            mGenerator.initialize(1024);
-            fail("KeyPairGenerator should not support setting the key size");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-
-    public void testKeyPairGenerator_Initialize_KeySizeAndSecureRandom_Encrypted_Failure()
-            throws Exception {
-        setupPassword();
-
-        try {
-            mGenerator.initialize(1024, new SecureRandom());
-            fail("KeyPairGenerator should not support setting the key size");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-
-    public void testKeyPairGenerator_Initialize_ParamsAndSecureRandom_Encrypted_Failure()
-            throws Exception {
-        setupPassword();
-
-        mGenerator.initialize(
-                new KeyPairGeneratorSpec.Builder(getContext())
-                        .setAlias(TEST_ALIAS_1)
-                        .setKeyType("RSA")
-                        .setKeySize(1024)
-                        .setSubject(TEST_DN_1)
-                        .setSerialNumber(TEST_SERIAL_1)
-                        .setStartDate(NOW)
-                        .setEndDate(NOW_PLUS_10_YEARS)
-                        .setEncryptionRequired()
-                        .build(),
-                new SecureRandom());
-    }
-
-    public void testKeyPairGenerator_GenerateKeyPair_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                .setAlias(TEST_ALIAS_1)
-                .setSubject(TEST_DN_1)
-                .setSerialNumber(TEST_SERIAL_1)
-                .setStartDate(NOW)
-                .setEndDate(NOW_PLUS_10_YEARS)
-                .setEncryptionRequired()
-                .build());
-
-        final KeyPair pair = mGenerator.generateKeyPair();
-        assertNotNull("The KeyPair returned should not be null", pair);
-
-        assertKeyPairCorrect(pair, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, NOW,
-                NOW_PLUS_10_YEARS);
-    }
-
-    public void testKeyPairGenerator_GenerateKeyPair_EC_Unencrypted_Success() throws Exception {
-        KeyPairGenerator generator = KeyPairGenerator.getInstance("EC", "AndroidKeyStore");
-        generator.initialize(new KeyGenParameterSpec.Builder(
-                TEST_ALIAS_1,
-                KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
-                .setCertificateSubject(TEST_DN_1)
-                .setCertificateSerialNumber(TEST_SERIAL_1)
-                .setCertificateNotBefore(NOW)
-                .setCertificateNotAfter(NOW_PLUS_10_YEARS)
-                .setDigests(KeyProperties.DIGEST_SHA256)
-                .build());
-
-        final KeyPair pair = generator.generateKeyPair();
-        assertNotNull("The KeyPair returned should not be null", pair);
-
-        assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 256, null, TEST_DN_1, TEST_SERIAL_1, NOW,
-                NOW_PLUS_10_YEARS);
-    }
-
-    public void testKeyPairGenerator_Legacy_GenerateKeyPair_EC_Unencrypted_Success()
-            throws Exception {
-        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                .setAlias(TEST_ALIAS_1)
-                .setKeyType("EC")
-                .setSubject(TEST_DN_1)
-                .setSerialNumber(TEST_SERIAL_1)
-                .setStartDate(NOW)
-                .setEndDate(NOW_PLUS_10_YEARS)
-                .build());
-
-        final KeyPair pair = mGenerator.generateKeyPair();
-        assertNotNull("The KeyPair returned should not be null", pair);
-
-        assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 256, null, TEST_DN_1, TEST_SERIAL_1, NOW,
-                NOW_PLUS_10_YEARS);
-    }
-
-    public void testKeyPairGenerator_GenerateKeyPair_EC_P521_Unencrypted_Success() throws Exception {
-        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                .setAlias(TEST_ALIAS_1)
-                .setKeyType("EC")
-                .setKeySize(521)
-                .setSubject(TEST_DN_1)
-                .setSerialNumber(TEST_SERIAL_1)
-                .setStartDate(NOW)
-                .setEndDate(NOW_PLUS_10_YEARS)
-                .build());
-
-        final KeyPair pair = mGenerator.generateKeyPair();
-        assertNotNull("The KeyPair returned should not be null", pair);
-
-        assertKeyPairCorrect(pair, TEST_ALIAS_1, "EC", 521, null, TEST_DN_1, TEST_SERIAL_1, NOW,
-                NOW_PLUS_10_YEARS);
-    }
-
-    public void testKeyPairGenerator_GenerateKeyPair_RSA_Unencrypted_Success() throws Exception {
-        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                .setAlias(TEST_ALIAS_1)
-                .setSubject(TEST_DN_1)
-                .setSerialNumber(TEST_SERIAL_1)
-                .setStartDate(NOW)
-                .setEndDate(NOW_PLUS_10_YEARS)
-                .build());
-
-        final KeyPair pair = mGenerator.generateKeyPair();
-        assertNotNull("The KeyPair returned should not be null", pair);
-
-        assertKeyPairCorrect(pair, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1, NOW,
-                NOW_PLUS_10_YEARS);
-    }
-
-    public void testKeyPairGenerator_GenerateKeyPair_RSA_WithParams_Unencrypted_Success()
-            throws Exception {
-        AlgorithmParameterSpec spec = new RSAKeyGenParameterSpec(1024, BigInteger.valueOf(3L));
-        mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                .setAlias(TEST_ALIAS_1)
-                .setKeySize(1024)
-                .setAlgorithmParameterSpec(spec)
-                .setSubject(TEST_DN_1)
-                .setSerialNumber(TEST_SERIAL_1)
-                .setStartDate(NOW)
-                .setEndDate(NOW_PLUS_10_YEARS)
-                .build());
-
-        final KeyPair pair = mGenerator.generateKeyPair();
-        assertNotNull("The KeyPair returned should not be null", pair);
-
-        assertKeyPairCorrect(pair, TEST_ALIAS_1, "RSA", 1024, spec, TEST_DN_1, TEST_SERIAL_1, NOW,
-                NOW_PLUS_10_YEARS);
-    }
-
-    public void testKeyPairGenerator_GenerateKeyPair_Replaced_Success() throws Exception {
-        // Generate the first key
-        {
-            mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                    .setAlias(TEST_ALIAS_1)
-                    .setSubject(TEST_DN_1)
-                    .setSerialNumber(TEST_SERIAL_1)
-                    .setStartDate(NOW)
-                    .setEndDate(NOW_PLUS_10_YEARS)
-                    .build());
-            final KeyPair pair1 = mGenerator.generateKeyPair();
-            assertNotNull("The KeyPair returned should not be null", pair1);
-            assertKeyPairCorrect(pair1, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1,
-                    NOW, NOW_PLUS_10_YEARS);
-        }
-
-        // Replace the original key
-        {
-            mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                    .setAlias(TEST_ALIAS_2)
-                    .setSubject(TEST_DN_2)
-                    .setSerialNumber(TEST_SERIAL_2)
-                    .setStartDate(NOW)
-                    .setEndDate(NOW_PLUS_10_YEARS)
-                    .build());
-            final KeyPair pair2 = mGenerator.generateKeyPair();
-            assertNotNull("The KeyPair returned should not be null", pair2);
-            assertKeyPairCorrect(pair2, TEST_ALIAS_2, "RSA", 2048, null, TEST_DN_2, TEST_SERIAL_2,
-                    NOW, NOW_PLUS_10_YEARS);
-        }
-    }
-
-    public void testKeyPairGenerator_GenerateKeyPair_Replaced_UnencryptedToEncrypted_Success()
-            throws Exception {
-        // Generate the first key
-        {
-            mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                    .setAlias(TEST_ALIAS_1)
-                    .setSubject(TEST_DN_1)
-                    .setSerialNumber(TEST_SERIAL_1)
-                    .setStartDate(NOW)
-                    .setEndDate(NOW_PLUS_10_YEARS)
-                    .build());
-            final KeyPair pair1 = mGenerator.generateKeyPair();
-            assertNotNull("The KeyPair returned should not be null", pair1);
-            assertKeyPairCorrect(pair1, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_1, TEST_SERIAL_1,
-                    NOW, NOW_PLUS_10_YEARS);
-        }
-
-        // Attempt to replace previous key
-        {
-            mGenerator.initialize(new KeyPairGeneratorSpec.Builder(getContext())
-                    .setAlias(TEST_ALIAS_1)
-                    .setSubject(TEST_DN_2)
-                    .setSerialNumber(TEST_SERIAL_2)
-                    .setStartDate(NOW)
-                    .setEndDate(NOW_PLUS_10_YEARS)
-                    .setEncryptionRequired()
-                    .build());
-            try {
-                mGenerator.generateKeyPair();
-                fail("Should not be able to generate encrypted key while not initialized");
-            } catch (IllegalStateException expected) {
-            }
-
-            assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111"));
-            assertTrue(mAndroidKeyStore.isUnlocked());
-
-            final KeyPair pair2 = mGenerator.generateKeyPair();
-            assertNotNull("The KeyPair returned should not be null", pair2);
-            assertKeyPairCorrect(pair2, TEST_ALIAS_1, "RSA", 2048, null, TEST_DN_2, TEST_SERIAL_2,
-                    NOW, NOW_PLUS_10_YEARS);
-        }
-    }
-
-    private void assertKeyPairCorrect(KeyPair pair, String alias, String keyType, int keySize,
-            AlgorithmParameterSpec spec, X500Principal dn, BigInteger serial, Date start, Date end)
-            throws Exception {
-        final PublicKey pubKey = pair.getPublic();
-        assertNotNull("The PublicKey for the KeyPair should be not null", pubKey);
-        assertEquals(keyType, pubKey.getAlgorithm());
-
-        if ("EC".equalsIgnoreCase(keyType)) {
-            assertEquals("Curve should be what was specified during initialization", keySize,
-                    ((ECPublicKey) pubKey).getParams().getCurve().getField().getFieldSize());
-        } else if ("RSA".equalsIgnoreCase(keyType)) {
-            RSAPublicKey rsaPubKey = (RSAPublicKey) pubKey;
-            assertEquals("Modulus size should be what is specified during initialization",
-                    (keySize + 7) & ~7, (rsaPubKey.getModulus().bitLength() + 7) & ~7);
-            if (spec != null) {
-                RSAKeyGenParameterSpec params = (RSAKeyGenParameterSpec) spec;
-                assertEquals((keySize + 7) & ~7, (params.getKeysize() + 7) & ~7);
-                assertEquals(params.getPublicExponent(), rsaPubKey.getPublicExponent());
-            }
-        }
-
-        final PrivateKey privKey = pair.getPrivate();
-        assertNotNull("The PrivateKey for the KeyPair should be not null", privKey);
-        assertEquals(keyType, privKey.getAlgorithm());
-
-        if ("EC".equalsIgnoreCase(keyType)) {
-            assertTrue("EC private key must be instanceof ECKey: " + privKey.getClass().getName(),
-                    privKey instanceof ECKey);
-            assertEquals("Private and public key must have the same EC parameters",
-                    ((ECKey) pubKey).getParams(), ((ECKey) privKey).getParams());
-        } else if ("RSA".equalsIgnoreCase(keyType)) {
-            assertTrue("RSA private key must be instance of RSAKey: "
-                    + privKey.getClass().getName(),
-                    privKey instanceof RSAKey);
-            assertEquals("Private and public key must have the same RSA modulus",
-                    ((RSAKey) pubKey).getModulus(), ((RSAKey) privKey).getModulus());
-        }
-
-        final byte[] userCertBytes = mAndroidKeyStore.get(Credentials.USER_CERTIFICATE + alias);
-        assertNotNull("The user certificate should exist for the generated entry", userCertBytes);
-
-        final CertificateFactory cf = CertificateFactory.getInstance("X.509");
-        final Certificate userCert =
-                cf.generateCertificate(new ByteArrayInputStream(userCertBytes));
-
-        assertTrue("Certificate should be in X.509 format", userCert instanceof X509Certificate);
-
-        final X509Certificate x509userCert = (X509Certificate) userCert;
-
-        assertEquals(
-                "Public key used to sign certificate should have the same algorithm as in KeyPair",
-                pubKey.getAlgorithm(), x509userCert.getPublicKey().getAlgorithm());
-
-        assertEquals("PublicKey used to sign certificate should match one returned in KeyPair",
-                pubKey,
-                AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
-                        Credentials.USER_PRIVATE_KEY + alias,
-                        KeyStore.UID_SELF,
-                        x509userCert.getPublicKey().getAlgorithm(),
-                        x509userCert.getPublicKey().getEncoded()));
-
-        assertEquals("The Subject DN should be the one passed into the params", dn,
-                x509userCert.getSubjectDN());
-
-        assertEquals("The Issuer DN should be the same as the Subject DN", dn,
-                x509userCert.getIssuerDN());
-
-        assertEquals("The Serial should be the one passed into the params", serial,
-                x509userCert.getSerialNumber());
-
-        assertDateEquals("The notBefore date should be the one passed into the params", start,
-                x509userCert.getNotBefore());
-
-        assertDateEquals("The notAfter date should be the one passed into the params", end,
-                x509userCert.getNotAfter());
-
-        // Assert that the cert's signature verifies using the public key from generated KeyPair
-        x509userCert.verify(pubKey);
-        // Assert that the cert's signature verifies using the public key from the cert itself.
-        x509userCert.verify(x509userCert.getPublicKey());
-
-        final byte[] caCerts = mAndroidKeyStore.get(Credentials.CA_CERTIFICATE + alias);
-        assertNull("A list of CA certificates should not exist for the generated entry", caCerts);
-
-        ExportResult exportResult = mAndroidKeyStore.exportKey(
-                Credentials.USER_PRIVATE_KEY + alias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null);
-        assertEquals(KeyStore.NO_ERROR, exportResult.resultCode);
-        final byte[] pubKeyBytes = exportResult.exportData;
-        assertNotNull("The keystore should return the public key for the generated key",
-                pubKeyBytes);
-        assertTrue("Public key X.509 format should be as expected",
-                Arrays.equals(pubKey.getEncoded(), pubKeyBytes));
-    }
-
-    private static void assertDateEquals(String message, Date date1, Date date2) throws Exception {
-        SimpleDateFormat formatter = new SimpleDateFormat("dd MMM yyyy HH:mm:ss");
-
-        String result1 = formatter.format(date1);
-        String result2 = formatter.format(date2);
-
-        assertEquals(message, result1, result2);
-    }
-}
diff --git a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java b/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
deleted file mode 100644
index aa718dc..0000000
--- a/keystore/tests/src/android/security/keystore/AndroidKeyStoreTest.java
+++ /dev/null
@@ -1,2210 +0,0 @@
-/*
- * Copyright (C) 2012 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 android.security.keystore;
-
-import com.android.org.bouncycastle.x509.X509V3CertificateGenerator;
-
-import com.android.org.conscrypt.NativeConstants;
-
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.security.KeyStoreParameter;
-import android.test.AndroidTestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.OutputStream;
-import java.math.BigInteger;
-import java.security.Key;
-import java.security.KeyFactory;
-import java.security.KeyPair;
-import java.security.KeyStore.Entry;
-import java.security.KeyStore.PrivateKeyEntry;
-import java.security.KeyStore.TrustedCertificateEntry;
-import java.security.KeyStoreException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.security.interfaces.ECKey;
-import java.security.interfaces.RSAKey;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import javax.crypto.Cipher;
-import javax.crypto.SecretKey;
-import javax.crypto.spec.SecretKeySpec;
-import javax.security.auth.x500.X500Principal;
-
-public class AndroidKeyStoreTest extends AndroidTestCase {
-    private android.security.KeyStore mAndroidKeyStore;
-
-    private java.security.KeyStore mKeyStore;
-
-    private static final String TEST_ALIAS_1 = "test1";
-
-    private static final String TEST_ALIAS_2 = "test2";
-
-    private static final String TEST_ALIAS_3 = "test3";
-
-    private static final X500Principal TEST_DN_1 = new X500Principal("CN=test1");
-
-    private static final X500Principal TEST_DN_2 = new X500Principal("CN=test2");
-
-    private static final BigInteger TEST_SERIAL_1 = BigInteger.ONE;
-
-    private static final BigInteger TEST_SERIAL_2 = BigInteger.valueOf(2L);
-
-    private static final long NOW_MILLIS = System.currentTimeMillis();
-
-    /* We have to round this off because X509v3 doesn't store milliseconds. */
-    private static final Date NOW = new Date(NOW_MILLIS - (NOW_MILLIS % 1000L));
-
-    @SuppressWarnings("deprecation")
-    private static final Date NOW_PLUS_10_YEARS = new Date(NOW.getYear() + 10, 0, 1);
-
-    /*
-     * The keys and certificates below are generated with:
-     *
-     * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
-     * openssl req -newkey rsa:1024 -keyout userkey.pem -nodes -days 3650 -out userkey.req
-     * mkdir -p demoCA/newcerts
-     * touch demoCA/index.txt
-     * echo "01" > demoCA/serial
-     * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
-     */
-
-    /**
-     * Generated from above and converted with:
-     *
-     * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
-     */
-    private static final byte[] FAKE_RSA_CA_1 = {
-            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0xce, (byte) 0x30, (byte) 0x82,
-            (byte) 0x02, (byte) 0x37, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
-            (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xe1, (byte) 0x6a,
-            (byte) 0xa2, (byte) 0xf4, (byte) 0x2e, (byte) 0x55, (byte) 0x48, (byte) 0x0a,
-            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
-            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
-            (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x4f, (byte) 0x31,
-            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53,
-            (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43,
-            (byte) 0x41, (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d,
-            (byte) 0x4d, (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61,
-            (byte) 0x69, (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65,
-            (byte) 0x77, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12,
-            (byte) 0x41, (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69,
-            (byte) 0x64, (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74,
-            (byte) 0x20, (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73,
-            (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x32,
-            (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x34, (byte) 0x31, (byte) 0x36,
-            (byte) 0x35, (byte) 0x35, (byte) 0x34, (byte) 0x34, (byte) 0x5a, (byte) 0x17,
-            (byte) 0x0d, (byte) 0x32, (byte) 0x32, (byte) 0x30, (byte) 0x38, (byte) 0x31,
-            (byte) 0x32, (byte) 0x31, (byte) 0x36, (byte) 0x35, (byte) 0x35, (byte) 0x34,
-            (byte) 0x34, (byte) 0x5a, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b,
-            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31,
-            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41,
-            (byte) 0x31, (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d,
-            (byte) 0x6f, (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69,
-            (byte) 0x6e, (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77,
-            (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41,
-            (byte) 0x6e, (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64,
-            (byte) 0x20, (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20,
-            (byte) 0x43, (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x30,
-            (byte) 0x81, (byte) 0x9f, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
-            (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
-            (byte) 0x01, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03,
-            (byte) 0x81, (byte) 0x8d, (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89,
-            (byte) 0x02, (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0xa3, (byte) 0x72,
-            (byte) 0xab, (byte) 0xd0, (byte) 0xe4, (byte) 0xad, (byte) 0x2f, (byte) 0xe7,
-            (byte) 0xe2, (byte) 0x79, (byte) 0x07, (byte) 0x36, (byte) 0x3d, (byte) 0x0c,
-            (byte) 0x8d, (byte) 0x42, (byte) 0x9a, (byte) 0x0a, (byte) 0x33, (byte) 0x64,
-            (byte) 0xb3, (byte) 0xcd, (byte) 0xb2, (byte) 0xd7, (byte) 0x3a, (byte) 0x42,
-            (byte) 0x06, (byte) 0x77, (byte) 0x45, (byte) 0x29, (byte) 0xe9, (byte) 0xcb,
-            (byte) 0xb7, (byte) 0x4a, (byte) 0xd6, (byte) 0xee, (byte) 0xad, (byte) 0x01,
-            (byte) 0x91, (byte) 0x9b, (byte) 0x0c, (byte) 0x59, (byte) 0xa1, (byte) 0x03,
-            (byte) 0xfa, (byte) 0xf0, (byte) 0x5a, (byte) 0x7c, (byte) 0x4f, (byte) 0xf7,
-            (byte) 0x8d, (byte) 0x36, (byte) 0x0f, (byte) 0x1f, (byte) 0x45, (byte) 0x7d,
-            (byte) 0x1b, (byte) 0x31, (byte) 0xa1, (byte) 0x35, (byte) 0x0b, (byte) 0x00,
-            (byte) 0xed, (byte) 0x7a, (byte) 0xb6, (byte) 0xc8, (byte) 0x4e, (byte) 0xa9,
-            (byte) 0x86, (byte) 0x4c, (byte) 0x7b, (byte) 0x99, (byte) 0x57, (byte) 0x41,
-            (byte) 0x12, (byte) 0xef, (byte) 0x6b, (byte) 0xbc, (byte) 0x3d, (byte) 0x60,
-            (byte) 0xf2, (byte) 0x99, (byte) 0x1a, (byte) 0xcd, (byte) 0xed, (byte) 0x56,
-            (byte) 0xa4, (byte) 0xe5, (byte) 0x36, (byte) 0x9f, (byte) 0x24, (byte) 0x1f,
-            (byte) 0xdc, (byte) 0x89, (byte) 0x40, (byte) 0xc8, (byte) 0x99, (byte) 0x92,
-            (byte) 0xab, (byte) 0x4a, (byte) 0xb5, (byte) 0x61, (byte) 0x45, (byte) 0x62,
-            (byte) 0xff, (byte) 0xa3, (byte) 0x45, (byte) 0x65, (byte) 0xaf, (byte) 0xf6,
-            (byte) 0x27, (byte) 0x30, (byte) 0x51, (byte) 0x0e, (byte) 0x0e, (byte) 0xeb,
-            (byte) 0x79, (byte) 0x0c, (byte) 0xbe, (byte) 0xb3, (byte) 0x0a, (byte) 0x6f,
-            (byte) 0x29, (byte) 0x06, (byte) 0xdc, (byte) 0x2f, (byte) 0x6b, (byte) 0x51,
-            (byte) 0x02, (byte) 0x03, (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3,
-            (byte) 0x81, (byte) 0xb1, (byte) 0x30, (byte) 0x81, (byte) 0xae, (byte) 0x30,
-            (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e,
-            (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x33, (byte) 0x05,
-            (byte) 0xee, (byte) 0xfe, (byte) 0x6f, (byte) 0x60, (byte) 0xc7, (byte) 0xf9,
-            (byte) 0xa9, (byte) 0xd2, (byte) 0x73, (byte) 0x5c, (byte) 0x8f, (byte) 0x6d,
-            (byte) 0xa2, (byte) 0x2f, (byte) 0x97, (byte) 0x8e, (byte) 0x5d, (byte) 0x51,
-            (byte) 0x30, (byte) 0x7f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d,
-            (byte) 0x23, (byte) 0x04, (byte) 0x78, (byte) 0x30, (byte) 0x76, (byte) 0x80,
-            (byte) 0x14, (byte) 0x33, (byte) 0x05, (byte) 0xee, (byte) 0xfe, (byte) 0x6f,
-            (byte) 0x60, (byte) 0xc7, (byte) 0xf9, (byte) 0xa9, (byte) 0xd2, (byte) 0x73,
-            (byte) 0x5c, (byte) 0x8f, (byte) 0x6d, (byte) 0xa2, (byte) 0x2f, (byte) 0x97,
-            (byte) 0x8e, (byte) 0x5d, (byte) 0x51, (byte) 0xa1, (byte) 0x53, (byte) 0xa4,
-            (byte) 0x51, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
-            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
-            (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b,
-            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31,
-            (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f,
-            (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e,
-            (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31,
-            (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e,
-            (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20,
-            (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43,
-            (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x82, (byte) 0x09,
-            (byte) 0x00, (byte) 0xe1, (byte) 0x6a, (byte) 0xa2, (byte) 0xf4, (byte) 0x2e,
-            (byte) 0x55, (byte) 0x48, (byte) 0x0a, (byte) 0x30, (byte) 0x0c, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x05,
-            (byte) 0x30, (byte) 0x03, (byte) 0x01, (byte) 0x01, (byte) 0xff, (byte) 0x30,
-            (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48,
-            (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05,
-            (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x81, (byte) 0x00,
-            (byte) 0x8c, (byte) 0x30, (byte) 0x42, (byte) 0xfa, (byte) 0xeb, (byte) 0x1a,
-            (byte) 0x26, (byte) 0xeb, (byte) 0xda, (byte) 0x56, (byte) 0x32, (byte) 0xf2,
-            (byte) 0x9d, (byte) 0xa5, (byte) 0x24, (byte) 0xd8, (byte) 0x3a, (byte) 0xda,
-            (byte) 0x30, (byte) 0xa6, (byte) 0x8b, (byte) 0x46, (byte) 0xfe, (byte) 0xfe,
-            (byte) 0xdb, (byte) 0xf1, (byte) 0xe6, (byte) 0xe1, (byte) 0x7c, (byte) 0x1b,
-            (byte) 0xe7, (byte) 0x77, (byte) 0x00, (byte) 0xa1, (byte) 0x1c, (byte) 0x19,
-            (byte) 0x17, (byte) 0x73, (byte) 0xb0, (byte) 0xf0, (byte) 0x9d, (byte) 0xf3,
-            (byte) 0x4f, (byte) 0xb6, (byte) 0xbc, (byte) 0xc7, (byte) 0x47, (byte) 0x85,
-            (byte) 0x2a, (byte) 0x4a, (byte) 0xa1, (byte) 0xa5, (byte) 0x58, (byte) 0xf5,
-            (byte) 0xc5, (byte) 0x1a, (byte) 0x51, (byte) 0xb1, (byte) 0x04, (byte) 0x80,
-            (byte) 0xee, (byte) 0x3a, (byte) 0xec, (byte) 0x2f, (byte) 0xe1, (byte) 0xfd,
-            (byte) 0x58, (byte) 0xeb, (byte) 0xed, (byte) 0x82, (byte) 0x9e, (byte) 0x38,
-            (byte) 0xa3, (byte) 0x24, (byte) 0x75, (byte) 0xf7, (byte) 0x3e, (byte) 0xc2,
-            (byte) 0xc5, (byte) 0x27, (byte) 0xeb, (byte) 0x6f, (byte) 0x7b, (byte) 0x50,
-            (byte) 0xda, (byte) 0x43, (byte) 0xdc, (byte) 0x3b, (byte) 0x0b, (byte) 0x6f,
-            (byte) 0x78, (byte) 0x8f, (byte) 0xb0, (byte) 0x66, (byte) 0xe1, (byte) 0x12,
-            (byte) 0x87, (byte) 0x5f, (byte) 0x97, (byte) 0x7b, (byte) 0xca, (byte) 0x14,
-            (byte) 0x79, (byte) 0xf7, (byte) 0xe8, (byte) 0x6c, (byte) 0x72, (byte) 0xdb,
-            (byte) 0x91, (byte) 0x65, (byte) 0x17, (byte) 0x54, (byte) 0xe0, (byte) 0x74,
-            (byte) 0x1d, (byte) 0xac, (byte) 0x47, (byte) 0x04, (byte) 0x12, (byte) 0xe0,
-            (byte) 0xc3, (byte) 0x66, (byte) 0x19, (byte) 0x05, (byte) 0x2e, (byte) 0x7e,
-            (byte) 0xf1, (byte) 0x61
-    };
-
-    /**
-     * Generated from above and converted with:
-     *
-     * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
-     */
-    private static final byte[] FAKE_RSA_KEY_1 = new byte[] {
-            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x78, (byte) 0x02, (byte) 0x01,
-            (byte) 0x00, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
-            (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01,
-            (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x82,
-            (byte) 0x02, (byte) 0x62, (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x5e,
-            (byte) 0x02, (byte) 0x01, (byte) 0x00, (byte) 0x02, (byte) 0x81, (byte) 0x81,
-            (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6, (byte) 0x5b,
-            (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c, (byte) 0x66,
-            (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86, (byte) 0x8a,
-            (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3, (byte) 0x02,
-            (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08, (byte) 0xf3,
-            (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04, (byte) 0x6d,
-            (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f, (byte) 0x67,
-            (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c, (byte) 0xcb,
-            (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30, (byte) 0xe2,
-            (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5, (byte) 0x79,
-            (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b, (byte) 0xce,
-            (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb, (byte) 0x08,
-            (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff, (byte) 0x3b,
-            (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9, (byte) 0xc4,
-            (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29, (byte) 0x0d,
-            (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b, (byte) 0x23,
-            (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78, (byte) 0x08,
-            (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5, (byte) 0xf1,
-            (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19, (byte) 0xb4,
-            (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03, (byte) 0x16,
-            (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce, (byte) 0x9e,
-            (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03, (byte) 0x01,
-            (byte) 0x00, (byte) 0x01, (byte) 0x02, (byte) 0x81, (byte) 0x80, (byte) 0x16,
-            (byte) 0x59, (byte) 0xc3, (byte) 0x24, (byte) 0x1d, (byte) 0x33, (byte) 0x98,
-            (byte) 0x9c, (byte) 0xc9, (byte) 0xc8, (byte) 0x2c, (byte) 0x88, (byte) 0xbf,
-            (byte) 0x0a, (byte) 0x01, (byte) 0xce, (byte) 0xfb, (byte) 0x34, (byte) 0x7a,
-            (byte) 0x58, (byte) 0x7a, (byte) 0xb0, (byte) 0xbf, (byte) 0xa6, (byte) 0xb2,
-            (byte) 0x60, (byte) 0xbe, (byte) 0x70, (byte) 0x21, (byte) 0xf5, (byte) 0xfc,
-            (byte) 0x85, (byte) 0x0d, (byte) 0x33, (byte) 0x58, (byte) 0xa1, (byte) 0xe5,
-            (byte) 0x09, (byte) 0x36, (byte) 0x84, (byte) 0xb2, (byte) 0x04, (byte) 0x0a,
-            (byte) 0x02, (byte) 0xd3, (byte) 0x88, (byte) 0x1f, (byte) 0x0c, (byte) 0x2b,
-            (byte) 0x1d, (byte) 0xe9, (byte) 0x3d, (byte) 0xe7, (byte) 0x79, (byte) 0xf9,
-            (byte) 0x32, (byte) 0x5c, (byte) 0x8a, (byte) 0x75, (byte) 0x49, (byte) 0x12,
-            (byte) 0xe4, (byte) 0x05, (byte) 0x26, (byte) 0xd4, (byte) 0x2e, (byte) 0x9e,
-            (byte) 0x1f, (byte) 0xcc, (byte) 0x54, (byte) 0xad, (byte) 0x33, (byte) 0x8d,
-            (byte) 0x99, (byte) 0x00, (byte) 0xdc, (byte) 0xf5, (byte) 0xb4, (byte) 0xa2,
-            (byte) 0x2f, (byte) 0xba, (byte) 0xe5, (byte) 0x62, (byte) 0x30, (byte) 0x6d,
-            (byte) 0xe6, (byte) 0x3d, (byte) 0xeb, (byte) 0x24, (byte) 0xc2, (byte) 0xdc,
-            (byte) 0x5f, (byte) 0xb7, (byte) 0x16, (byte) 0x35, (byte) 0xa3, (byte) 0x98,
-            (byte) 0x98, (byte) 0xa8, (byte) 0xef, (byte) 0xe8, (byte) 0xc4, (byte) 0x96,
-            (byte) 0x6d, (byte) 0x38, (byte) 0xab, (byte) 0x26, (byte) 0x6d, (byte) 0x30,
-            (byte) 0xc2, (byte) 0xa0, (byte) 0x44, (byte) 0xe4, (byte) 0xff, (byte) 0x7e,
-            (byte) 0xbe, (byte) 0x7c, (byte) 0x33, (byte) 0xa5, (byte) 0x10, (byte) 0xad,
-            (byte) 0xd7, (byte) 0x1e, (byte) 0x13, (byte) 0x20, (byte) 0xb3, (byte) 0x1f,
-            (byte) 0x41, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xf1, (byte) 0x89,
-            (byte) 0x07, (byte) 0x0f, (byte) 0xe8, (byte) 0xcf, (byte) 0xab, (byte) 0x13,
-            (byte) 0x2a, (byte) 0x8f, (byte) 0x88, (byte) 0x80, (byte) 0x11, (byte) 0x9a,
-            (byte) 0x79, (byte) 0xb6, (byte) 0x59, (byte) 0x3a, (byte) 0x50, (byte) 0x6e,
-            (byte) 0x57, (byte) 0x37, (byte) 0xab, (byte) 0x2a, (byte) 0xd2, (byte) 0xaa,
-            (byte) 0xd9, (byte) 0x72, (byte) 0x73, (byte) 0xff, (byte) 0x8b, (byte) 0x47,
-            (byte) 0x76, (byte) 0xdd, (byte) 0xdc, (byte) 0xf5, (byte) 0x97, (byte) 0x44,
-            (byte) 0x3a, (byte) 0x78, (byte) 0xbe, (byte) 0x17, (byte) 0xb4, (byte) 0x22,
-            (byte) 0x6f, (byte) 0xe5, (byte) 0x23, (byte) 0x70, (byte) 0x1d, (byte) 0x10,
-            (byte) 0x5d, (byte) 0xba, (byte) 0x16, (byte) 0x81, (byte) 0xf1, (byte) 0x45,
-            (byte) 0xce, (byte) 0x30, (byte) 0xb4, (byte) 0xab, (byte) 0x80, (byte) 0xe4,
-            (byte) 0x98, (byte) 0x31, (byte) 0x02, (byte) 0x41, (byte) 0x00, (byte) 0xda,
-            (byte) 0x82, (byte) 0x9d, (byte) 0x3f, (byte) 0xca, (byte) 0x2f, (byte) 0xe1,
-            (byte) 0xd4, (byte) 0x86, (byte) 0x77, (byte) 0x48, (byte) 0xa6, (byte) 0xab,
-            (byte) 0xab, (byte) 0x1c, (byte) 0x42, (byte) 0x5c, (byte) 0xd5, (byte) 0xc7,
-            (byte) 0x46, (byte) 0x59, (byte) 0x91, (byte) 0x3f, (byte) 0xfc, (byte) 0xcc,
-            (byte) 0xec, (byte) 0xc2, (byte) 0x40, (byte) 0x12, (byte) 0x2c, (byte) 0x8d,
-            (byte) 0x1f, (byte) 0xa2, (byte) 0x18, (byte) 0x88, (byte) 0xee, (byte) 0x82,
-            (byte) 0x4a, (byte) 0x5a, (byte) 0x5e, (byte) 0x88, (byte) 0x20, (byte) 0xe3,
-            (byte) 0x7b, (byte) 0xe0, (byte) 0xd8, (byte) 0x3a, (byte) 0x52, (byte) 0x9a,
-            (byte) 0x26, (byte) 0x6a, (byte) 0x04, (byte) 0xec, (byte) 0xe8, (byte) 0xb9,
-            (byte) 0x48, (byte) 0x40, (byte) 0xe1, (byte) 0xe1, (byte) 0x83, (byte) 0xa6,
-            (byte) 0x67, (byte) 0xa6, (byte) 0xfd, (byte) 0x02, (byte) 0x41, (byte) 0x00,
-            (byte) 0x89, (byte) 0x72, (byte) 0x3e, (byte) 0xb0, (byte) 0x90, (byte) 0xfd,
-            (byte) 0x4c, (byte) 0x0e, (byte) 0xd6, (byte) 0x13, (byte) 0x63, (byte) 0xcb,
-            (byte) 0xed, (byte) 0x38, (byte) 0x88, (byte) 0xb6, (byte) 0x79, (byte) 0xc4,
-            (byte) 0x33, (byte) 0x6c, (byte) 0xf6, (byte) 0xf8, (byte) 0xd8, (byte) 0xd0,
-            (byte) 0xbf, (byte) 0x9d, (byte) 0x35, (byte) 0xac, (byte) 0x69, (byte) 0xd2,
-            (byte) 0x2b, (byte) 0xc1, (byte) 0xf9, (byte) 0x24, (byte) 0x7b, (byte) 0xce,
-            (byte) 0xcd, (byte) 0xcb, (byte) 0xa7, (byte) 0xb2, (byte) 0x7a, (byte) 0x0a,
-            (byte) 0x27, (byte) 0x19, (byte) 0xc9, (byte) 0xaf, (byte) 0x0d, (byte) 0x21,
-            (byte) 0x89, (byte) 0x88, (byte) 0x7c, (byte) 0xad, (byte) 0x9e, (byte) 0x8d,
-            (byte) 0x47, (byte) 0x6d, (byte) 0x3f, (byte) 0xce, (byte) 0x7b, (byte) 0xa1,
-            (byte) 0x74, (byte) 0xf1, (byte) 0xa0, (byte) 0xa1, (byte) 0x02, (byte) 0x41,
-            (byte) 0x00, (byte) 0xd9, (byte) 0xa8, (byte) 0xf5, (byte) 0xfe, (byte) 0xce,
-            (byte) 0xe6, (byte) 0x77, (byte) 0x6b, (byte) 0xfe, (byte) 0x2d, (byte) 0xe0,
-            (byte) 0x1e, (byte) 0xb6, (byte) 0x2e, (byte) 0x12, (byte) 0x4e, (byte) 0x40,
-            (byte) 0xaf, (byte) 0x6a, (byte) 0x7b, (byte) 0x37, (byte) 0x49, (byte) 0x2a,
-            (byte) 0x96, (byte) 0x25, (byte) 0x83, (byte) 0x49, (byte) 0xd4, (byte) 0x0c,
-            (byte) 0xc6, (byte) 0x78, (byte) 0x25, (byte) 0x24, (byte) 0x90, (byte) 0x90,
-            (byte) 0x06, (byte) 0x15, (byte) 0x9e, (byte) 0xfe, (byte) 0xf9, (byte) 0xdf,
-            (byte) 0x5b, (byte) 0xf3, (byte) 0x7e, (byte) 0x38, (byte) 0x70, (byte) 0xeb,
-            (byte) 0x57, (byte) 0xd0, (byte) 0xd9, (byte) 0xa7, (byte) 0x0e, (byte) 0x14,
-            (byte) 0xf7, (byte) 0x95, (byte) 0x68, (byte) 0xd5, (byte) 0xc8, (byte) 0xab,
-            (byte) 0x9d, (byte) 0x3a, (byte) 0x2b, (byte) 0x51, (byte) 0xf9, (byte) 0x02,
-            (byte) 0x41, (byte) 0x00, (byte) 0x96, (byte) 0xdf, (byte) 0xe9, (byte) 0x67,
-            (byte) 0x6c, (byte) 0xdc, (byte) 0x90, (byte) 0x14, (byte) 0xb4, (byte) 0x1d,
-            (byte) 0x22, (byte) 0x33, (byte) 0x4a, (byte) 0x31, (byte) 0xc1, (byte) 0x9d,
-            (byte) 0x2e, (byte) 0xff, (byte) 0x9a, (byte) 0x2a, (byte) 0x95, (byte) 0x4b,
-            (byte) 0x27, (byte) 0x74, (byte) 0xcb, (byte) 0x21, (byte) 0xc3, (byte) 0xd2,
-            (byte) 0x0b, (byte) 0xb2, (byte) 0x46, (byte) 0x87, (byte) 0xf8, (byte) 0x28,
-            (byte) 0x01, (byte) 0x8b, (byte) 0xd8, (byte) 0xb9, (byte) 0x4b, (byte) 0xcd,
-            (byte) 0x9a, (byte) 0x96, (byte) 0x41, (byte) 0x0e, (byte) 0x36, (byte) 0x6d,
-            (byte) 0x40, (byte) 0x42, (byte) 0xbc, (byte) 0xd9, (byte) 0xd3, (byte) 0x7b,
-            (byte) 0xbc, (byte) 0xa7, (byte) 0x92, (byte) 0x90, (byte) 0xdd, (byte) 0xa1,
-            (byte) 0x9c, (byte) 0xce, (byte) 0xa1, (byte) 0x87, (byte) 0x11, (byte) 0x51
-    };
-
-    /**
-     * Generated from above and converted with:
-     *
-     * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
-     */
-    private static final byte[] FAKE_RSA_USER_1 = new byte[] {
-            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x95, (byte) 0x30, (byte) 0x82,
-            (byte) 0x01, (byte) 0xfe, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
-            (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d,
-            (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
-            (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05,
-            (byte) 0x00, (byte) 0x30, (byte) 0x4f, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
-            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
-            (byte) 0x13, (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b,
-            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x08, (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31,
-            (byte) 0x16, (byte) 0x30, (byte) 0x14, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x07, (byte) 0x13, (byte) 0x0d, (byte) 0x4d, (byte) 0x6f,
-            (byte) 0x75, (byte) 0x6e, (byte) 0x74, (byte) 0x61, (byte) 0x69, (byte) 0x6e,
-            (byte) 0x20, (byte) 0x56, (byte) 0x69, (byte) 0x65, (byte) 0x77, (byte) 0x31,
-            (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e,
-            (byte) 0x64, (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20,
-            (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43,
-            (byte) 0x61, (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x30, (byte) 0x1e,
-            (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x32, (byte) 0x30, (byte) 0x38,
-            (byte) 0x31, (byte) 0x34, (byte) 0x32, (byte) 0x33, (byte) 0x32, (byte) 0x35,
-            (byte) 0x34, (byte) 0x38, (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32,
-            (byte) 0x32, (byte) 0x30, (byte) 0x38, (byte) 0x31, (byte) 0x32, (byte) 0x32,
-            (byte) 0x33, (byte) 0x32, (byte) 0x35, (byte) 0x34, (byte) 0x38, (byte) 0x5a,
-            (byte) 0x30, (byte) 0x55, (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13,
-            (byte) 0x02, (byte) 0x55, (byte) 0x53, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
-            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08,
-            (byte) 0x13, (byte) 0x02, (byte) 0x43, (byte) 0x41, (byte) 0x31, (byte) 0x1b,
-            (byte) 0x30, (byte) 0x19, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x0a, (byte) 0x13, (byte) 0x12, (byte) 0x41, (byte) 0x6e, (byte) 0x64,
-            (byte) 0x72, (byte) 0x6f, (byte) 0x69, (byte) 0x64, (byte) 0x20, (byte) 0x54,
-            (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x20, (byte) 0x43, (byte) 0x61,
-            (byte) 0x73, (byte) 0x65, (byte) 0x73, (byte) 0x31, (byte) 0x1c, (byte) 0x30,
-            (byte) 0x1a, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03,
-            (byte) 0x13, (byte) 0x13, (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76,
-            (byte) 0x65, (byte) 0x72, (byte) 0x31, (byte) 0x2e, (byte) 0x65, (byte) 0x78,
-            (byte) 0x61, (byte) 0x6d, (byte) 0x70, (byte) 0x6c, (byte) 0x65, (byte) 0x2e,
-            (byte) 0x63, (byte) 0x6f, (byte) 0x6d, (byte) 0x30, (byte) 0x81, (byte) 0x9f,
-            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
-            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
-            (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8d,
-            (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81,
-            (byte) 0x81, (byte) 0x00, (byte) 0xce, (byte) 0x29, (byte) 0xeb, (byte) 0xf6,
-            (byte) 0x5b, (byte) 0x25, (byte) 0xdc, (byte) 0xa1, (byte) 0xa6, (byte) 0x2c,
-            (byte) 0x66, (byte) 0xcb, (byte) 0x20, (byte) 0x90, (byte) 0x27, (byte) 0x86,
-            (byte) 0x8a, (byte) 0x44, (byte) 0x71, (byte) 0x50, (byte) 0xda, (byte) 0xd3,
-            (byte) 0x02, (byte) 0x77, (byte) 0x55, (byte) 0xe9, (byte) 0xe8, (byte) 0x08,
-            (byte) 0xf3, (byte) 0x36, (byte) 0x9a, (byte) 0xae, (byte) 0xab, (byte) 0x04,
-            (byte) 0x6d, (byte) 0x00, (byte) 0x99, (byte) 0xbf, (byte) 0x7d, (byte) 0x0f,
-            (byte) 0x67, (byte) 0x8b, (byte) 0x1d, (byte) 0xd4, (byte) 0x2b, (byte) 0x7c,
-            (byte) 0xcb, (byte) 0xcd, (byte) 0x33, (byte) 0xc7, (byte) 0x84, (byte) 0x30,
-            (byte) 0xe2, (byte) 0x45, (byte) 0x21, (byte) 0xb3, (byte) 0x75, (byte) 0xf5,
-            (byte) 0x79, (byte) 0x02, (byte) 0xda, (byte) 0x50, (byte) 0xa3, (byte) 0x8b,
-            (byte) 0xce, (byte) 0xc3, (byte) 0x8e, (byte) 0x0f, (byte) 0x25, (byte) 0xeb,
-            (byte) 0x08, (byte) 0x2c, (byte) 0xdd, (byte) 0x1c, (byte) 0xcf, (byte) 0xff,
-            (byte) 0x3b, (byte) 0xde, (byte) 0xb6, (byte) 0xaa, (byte) 0x2a, (byte) 0xa9,
-            (byte) 0xc4, (byte) 0x8a, (byte) 0x24, (byte) 0x24, (byte) 0xe6, (byte) 0x29,
-            (byte) 0x0d, (byte) 0x98, (byte) 0x4c, (byte) 0x32, (byte) 0xa1, (byte) 0x7b,
-            (byte) 0x23, (byte) 0x2b, (byte) 0x42, (byte) 0x30, (byte) 0xee, (byte) 0x78,
-            (byte) 0x08, (byte) 0x47, (byte) 0xad, (byte) 0xf2, (byte) 0x96, (byte) 0xd5,
-            (byte) 0xf1, (byte) 0x62, (byte) 0x42, (byte) 0x2d, (byte) 0x35, (byte) 0x19,
-            (byte) 0xb4, (byte) 0x3c, (byte) 0xc9, (byte) 0xc3, (byte) 0x5f, (byte) 0x03,
-            (byte) 0x16, (byte) 0x3a, (byte) 0x23, (byte) 0xac, (byte) 0xcb, (byte) 0xce,
-            (byte) 0x9e, (byte) 0x51, (byte) 0x2e, (byte) 0x6d, (byte) 0x02, (byte) 0x03,
-            (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3, (byte) 0x7b, (byte) 0x30,
-            (byte) 0x79, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x1d, (byte) 0x13, (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00,
-            (byte) 0x30, (byte) 0x2c, (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86,
-            (byte) 0x48, (byte) 0x01, (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01,
-            (byte) 0x0d, (byte) 0x04, (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f,
-            (byte) 0x70, (byte) 0x65, (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c,
-            (byte) 0x20, (byte) 0x47, (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72,
-            (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43,
-            (byte) 0x65, (byte) 0x72, (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69,
-            (byte) 0x63, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04,
-            (byte) 0x16, (byte) 0x04, (byte) 0x14, (byte) 0x32, (byte) 0xa1, (byte) 0x1e,
-            (byte) 0x6b, (byte) 0x69, (byte) 0x04, (byte) 0xfe, (byte) 0xb3, (byte) 0xcd,
-            (byte) 0xf8, (byte) 0xbb, (byte) 0x14, (byte) 0xcd, (byte) 0xff, (byte) 0xd4,
-            (byte) 0x16, (byte) 0xc3, (byte) 0xab, (byte) 0x44, (byte) 0x2f, (byte) 0x30,
-            (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23,
-            (byte) 0x04, (byte) 0x18, (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14,
-            (byte) 0x33, (byte) 0x05, (byte) 0xee, (byte) 0xfe, (byte) 0x6f, (byte) 0x60,
-            (byte) 0xc7, (byte) 0xf9, (byte) 0xa9, (byte) 0xd2, (byte) 0x73, (byte) 0x5c,
-            (byte) 0x8f, (byte) 0x6d, (byte) 0xa2, (byte) 0x2f, (byte) 0x97, (byte) 0x8e,
-            (byte) 0x5d, (byte) 0x51, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09,
-            (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d,
-            (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03,
-            (byte) 0x81, (byte) 0x81, (byte) 0x00, (byte) 0x46, (byte) 0x42, (byte) 0xef,
-            (byte) 0x56, (byte) 0x89, (byte) 0x78, (byte) 0x90, (byte) 0x38, (byte) 0x24,
-            (byte) 0x9f, (byte) 0x8c, (byte) 0x7a, (byte) 0xce, (byte) 0x7a, (byte) 0xa5,
-            (byte) 0xb5, (byte) 0x1e, (byte) 0x74, (byte) 0x96, (byte) 0x34, (byte) 0x49,
-            (byte) 0x8b, (byte) 0xed, (byte) 0x44, (byte) 0xb3, (byte) 0xc9, (byte) 0x05,
-            (byte) 0xd7, (byte) 0x48, (byte) 0x55, (byte) 0x52, (byte) 0x59, (byte) 0x15,
-            (byte) 0x0b, (byte) 0xaa, (byte) 0x16, (byte) 0x86, (byte) 0xd2, (byte) 0x8e,
-            (byte) 0x16, (byte) 0x99, (byte) 0xe8, (byte) 0x5f, (byte) 0x11, (byte) 0x71,
-            (byte) 0x42, (byte) 0x55, (byte) 0xd1, (byte) 0xc4, (byte) 0x6f, (byte) 0x2e,
-            (byte) 0xa9, (byte) 0x64, (byte) 0x6f, (byte) 0xd8, (byte) 0xfd, (byte) 0x43,
-            (byte) 0x13, (byte) 0x24, (byte) 0xaa, (byte) 0x67, (byte) 0xe6, (byte) 0xf5,
-            (byte) 0xca, (byte) 0x80, (byte) 0x5e, (byte) 0x3a, (byte) 0x3e, (byte) 0xcc,
-            (byte) 0x4f, (byte) 0xba, (byte) 0x87, (byte) 0xe6, (byte) 0xae, (byte) 0xbf,
-            (byte) 0x8f, (byte) 0xd5, (byte) 0x28, (byte) 0x38, (byte) 0x58, (byte) 0x30,
-            (byte) 0x24, (byte) 0xf6, (byte) 0x53, (byte) 0x5b, (byte) 0x41, (byte) 0x53,
-            (byte) 0xe6, (byte) 0x45, (byte) 0xbc, (byte) 0xbe, (byte) 0xe6, (byte) 0xbb,
-            (byte) 0x5d, (byte) 0xd8, (byte) 0xa7, (byte) 0xf9, (byte) 0x64, (byte) 0x99,
-            (byte) 0x04, (byte) 0x43, (byte) 0x75, (byte) 0xd7, (byte) 0x2d, (byte) 0x32,
-            (byte) 0x0a, (byte) 0x94, (byte) 0xaf, (byte) 0x06, (byte) 0x34, (byte) 0xae,
-            (byte) 0x46, (byte) 0xbd, (byte) 0xda, (byte) 0x00, (byte) 0x0e, (byte) 0x25,
-            (byte) 0xc2, (byte) 0xf7, (byte) 0xc9, (byte) 0xc3, (byte) 0x65, (byte) 0xd2,
-            (byte) 0x08, (byte) 0x41, (byte) 0x0a, (byte) 0xf3, (byte) 0x72
-    };
-
-    /*
-     * The keys and certificates below are generated with:
-     *
-     * openssl req -new -x509 -days 3650 -extensions v3_ca -keyout cakey.pem -out cacert.pem
-     * openssl ecparam -name prime256v1 -out ecparam.pem
-     * openssl req -newkey ec:ecparam.pem -keyout userkey.pem -nodes -days 3650 -out userkey.req
-     * mkdir -p demoCA/newcerts
-     * touch demoCA/index.txt
-     * echo "01" > demoCA/serial
-     * openssl ca -out usercert.pem -in userkey.req -cert cacert.pem -keyfile cakey.pem -days 3650
-     */
-
-    /**
-     * Generated from above and converted with:
-     *
-     * openssl x509 -outform d -in cacert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
-     */
-    private static final byte[] FAKE_EC_CA_1 = {
-            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x58, (byte) 0x30, (byte) 0x82,
-            (byte) 0x01, (byte) 0xc1, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
-            (byte) 0x02, (byte) 0x02, (byte) 0x09, (byte) 0x00, (byte) 0xe1, (byte) 0xb2,
-            (byte) 0x8c, (byte) 0x04, (byte) 0x95, (byte) 0xeb, (byte) 0x10, (byte) 0xcb,
-            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
-            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
-            (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x30, (byte) 0x45, (byte) 0x31,
-            (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55,
-            (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53,
-            (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74,
-            (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30,
-            (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a,
-            (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65,
-            (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57,
-            (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73,
-            (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c,
-            (byte) 0x74, (byte) 0x64, (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d,
-            (byte) 0x31, (byte) 0x33, (byte) 0x30, (byte) 0x38, (byte) 0x32, (byte) 0x37,
-            (byte) 0x31, (byte) 0x36, (byte) 0x32, (byte) 0x38, (byte) 0x32, (byte) 0x38,
-            (byte) 0x5a, (byte) 0x17, (byte) 0x0d, (byte) 0x32, (byte) 0x33, (byte) 0x30,
-            (byte) 0x38, (byte) 0x32, (byte) 0x35, (byte) 0x31, (byte) 0x36, (byte) 0x32,
-            (byte) 0x38, (byte) 0x32, (byte) 0x38, (byte) 0x5a, (byte) 0x30, (byte) 0x45,
-            (byte) 0x31, (byte) 0x0b, (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x04, (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41,
-            (byte) 0x55, (byte) 0x31, (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a,
-            (byte) 0x53, (byte) 0x6f, (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53,
-            (byte) 0x74, (byte) 0x61, (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21,
-            (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x0a, (byte) 0x0c, (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74,
-            (byte) 0x65, (byte) 0x72, (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20,
-            (byte) 0x57, (byte) 0x69, (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74,
-            (byte) 0x73, (byte) 0x20, (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20,
-            (byte) 0x4c, (byte) 0x74, (byte) 0x64, (byte) 0x30, (byte) 0x81, (byte) 0x9f,
-            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
-            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
-            (byte) 0x01, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x8d,
-            (byte) 0x00, (byte) 0x30, (byte) 0x81, (byte) 0x89, (byte) 0x02, (byte) 0x81,
-            (byte) 0x81, (byte) 0x00, (byte) 0xb5, (byte) 0xf6, (byte) 0x08, (byte) 0x0f,
-            (byte) 0xc4, (byte) 0x4d, (byte) 0xe4, (byte) 0x0d, (byte) 0x34, (byte) 0x1d,
-            (byte) 0xe2, (byte) 0x23, (byte) 0x18, (byte) 0x63, (byte) 0x03, (byte) 0xf7,
-            (byte) 0x14, (byte) 0x0e, (byte) 0x98, (byte) 0xcd, (byte) 0x45, (byte) 0x1f,
-            (byte) 0xfe, (byte) 0xfb, (byte) 0x09, (byte) 0x3f, (byte) 0x5d, (byte) 0x36,
-            (byte) 0x3b, (byte) 0x0f, (byte) 0xf9, (byte) 0x5e, (byte) 0x86, (byte) 0x56,
-            (byte) 0x64, (byte) 0xd7, (byte) 0x3f, (byte) 0xae, (byte) 0x33, (byte) 0x09,
-            (byte) 0xd3, (byte) 0xdd, (byte) 0x06, (byte) 0x17, (byte) 0x26, (byte) 0xdc,
-            (byte) 0xa2, (byte) 0x8c, (byte) 0x3c, (byte) 0x65, (byte) 0xed, (byte) 0x03,
-            (byte) 0x82, (byte) 0x78, (byte) 0x9b, (byte) 0xee, (byte) 0xe3, (byte) 0x98,
-            (byte) 0x58, (byte) 0xe1, (byte) 0xf1, (byte) 0xa0, (byte) 0x85, (byte) 0xae,
-            (byte) 0x63, (byte) 0x84, (byte) 0x41, (byte) 0x46, (byte) 0xa7, (byte) 0x4f,
-            (byte) 0xdc, (byte) 0xbb, (byte) 0x1c, (byte) 0x6e, (byte) 0xec, (byte) 0x7b,
-            (byte) 0xd5, (byte) 0xab, (byte) 0x3d, (byte) 0x6a, (byte) 0x05, (byte) 0x58,
-            (byte) 0x0f, (byte) 0x9b, (byte) 0x6a, (byte) 0x67, (byte) 0x4b, (byte) 0xe9,
-            (byte) 0x2a, (byte) 0x6d, (byte) 0x96, (byte) 0x11, (byte) 0x53, (byte) 0x95,
-            (byte) 0x78, (byte) 0xaa, (byte) 0xd1, (byte) 0x91, (byte) 0x4a, (byte) 0xf8,
-            (byte) 0x54, (byte) 0x52, (byte) 0x6d, (byte) 0xb9, (byte) 0xca, (byte) 0x74,
-            (byte) 0x81, (byte) 0xf8, (byte) 0x99, (byte) 0x64, (byte) 0xd1, (byte) 0x4f,
-            (byte) 0x01, (byte) 0x38, (byte) 0x4f, (byte) 0x08, (byte) 0x5c, (byte) 0x31,
-            (byte) 0xcb, (byte) 0x7c, (byte) 0x5c, (byte) 0x78, (byte) 0x5d, (byte) 0x47,
-            (byte) 0xd9, (byte) 0xf0, (byte) 0x1a, (byte) 0xeb, (byte) 0x02, (byte) 0x03,
-            (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0xa3, (byte) 0x50, (byte) 0x30,
-            (byte) 0x4e, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04, (byte) 0x14,
-            (byte) 0x5f, (byte) 0x5b, (byte) 0x5e, (byte) 0xac, (byte) 0x29, (byte) 0xfa,
-            (byte) 0xa1, (byte) 0x9f, (byte) 0x9e, (byte) 0xad, (byte) 0x46, (byte) 0xe1,
-            (byte) 0xbc, (byte) 0x20, (byte) 0x72, (byte) 0xcf, (byte) 0x4a, (byte) 0xd4,
-            (byte) 0xfa, (byte) 0xe3, (byte) 0x30, (byte) 0x1f, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18, (byte) 0x30,
-            (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x5f, (byte) 0x5b, (byte) 0x5e,
-            (byte) 0xac, (byte) 0x29, (byte) 0xfa, (byte) 0xa1, (byte) 0x9f, (byte) 0x9e,
-            (byte) 0xad, (byte) 0x46, (byte) 0xe1, (byte) 0xbc, (byte) 0x20, (byte) 0x72,
-            (byte) 0xcf, (byte) 0x4a, (byte) 0xd4, (byte) 0xfa, (byte) 0xe3, (byte) 0x30,
-            (byte) 0x0c, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13,
-            (byte) 0x04, (byte) 0x05, (byte) 0x30, (byte) 0x03, (byte) 0x01, (byte) 0x01,
-            (byte) 0xff, (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a,
-            (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01,
-            (byte) 0x01, (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81,
-            (byte) 0x81, (byte) 0x00, (byte) 0xa1, (byte) 0x4a, (byte) 0xe6, (byte) 0xfc,
-            (byte) 0x7f, (byte) 0x17, (byte) 0xaa, (byte) 0x65, (byte) 0x4a, (byte) 0x34,
-            (byte) 0xde, (byte) 0x69, (byte) 0x67, (byte) 0x54, (byte) 0x4d, (byte) 0xa2,
-            (byte) 0xc2, (byte) 0x98, (byte) 0x02, (byte) 0x43, (byte) 0x6a, (byte) 0x0e,
-            (byte) 0x0b, (byte) 0x7f, (byte) 0xa4, (byte) 0x46, (byte) 0xaf, (byte) 0xa4,
-            (byte) 0x65, (byte) 0xa0, (byte) 0xdb, (byte) 0xf1, (byte) 0x5b, (byte) 0xd5,
-            (byte) 0x09, (byte) 0xbc, (byte) 0xee, (byte) 0x37, (byte) 0x51, (byte) 0x19,
-            (byte) 0x36, (byte) 0xc0, (byte) 0x90, (byte) 0xd3, (byte) 0x5f, (byte) 0xf3,
-            (byte) 0x4f, (byte) 0xb9, (byte) 0x08, (byte) 0x45, (byte) 0x0e, (byte) 0x01,
-            (byte) 0x8a, (byte) 0x95, (byte) 0xef, (byte) 0x92, (byte) 0x95, (byte) 0x33,
-            (byte) 0x78, (byte) 0xdd, (byte) 0x90, (byte) 0xbb, (byte) 0xf3, (byte) 0x06,
-            (byte) 0x75, (byte) 0xd0, (byte) 0x66, (byte) 0xe6, (byte) 0xd0, (byte) 0x18,
-            (byte) 0x6e, (byte) 0xeb, (byte) 0x1c, (byte) 0x52, (byte) 0xc3, (byte) 0x2e,
-            (byte) 0x57, (byte) 0x7d, (byte) 0xa9, (byte) 0x03, (byte) 0xdb, (byte) 0xf4,
-            (byte) 0x57, (byte) 0x5f, (byte) 0x6c, (byte) 0x7e, (byte) 0x00, (byte) 0x0d,
-            (byte) 0x8f, (byte) 0xe8, (byte) 0x91, (byte) 0xf7, (byte) 0xae, (byte) 0x24,
-            (byte) 0x35, (byte) 0x07, (byte) 0xb5, (byte) 0x48, (byte) 0x2d, (byte) 0x36,
-            (byte) 0x30, (byte) 0x5d, (byte) 0xe9, (byte) 0x49, (byte) 0x2d, (byte) 0xd1,
-            (byte) 0x5d, (byte) 0xc5, (byte) 0xf4, (byte) 0x33, (byte) 0x77, (byte) 0x3c,
-            (byte) 0x71, (byte) 0xad, (byte) 0x90, (byte) 0x65, (byte) 0xa9, (byte) 0xc1,
-            (byte) 0x0b, (byte) 0x5c, (byte) 0x62, (byte) 0x55, (byte) 0x50, (byte) 0x6f,
-            (byte) 0x9b, (byte) 0xc9, (byte) 0x0d, (byte) 0xee
-    };
-
-    /**
-     * Generated from above and converted with:
-     *
-     * openssl pkcs8 -topk8 -outform d -in userkey.pem -nocrypt | xxd -i | sed 's/0x/(byte) 0x/g'
-     */
-    private static final byte[] FAKE_EC_KEY_1 = new byte[] {
-            (byte) 0x30, (byte) 0x81, (byte) 0x87, (byte) 0x02, (byte) 0x01, (byte) 0x00,
-            (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07, (byte) 0x2a, (byte) 0x86,
-            (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02, (byte) 0x01, (byte) 0x06,
-            (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d,
-            (byte) 0x03, (byte) 0x01, (byte) 0x07, (byte) 0x04, (byte) 0x6d, (byte) 0x30,
-            (byte) 0x6b, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x04, (byte) 0x20,
-            (byte) 0x3a, (byte) 0x8a, (byte) 0x02, (byte) 0xdc, (byte) 0xde, (byte) 0x70,
-            (byte) 0x84, (byte) 0x45, (byte) 0x34, (byte) 0xaf, (byte) 0xbd, (byte) 0xd5,
-            (byte) 0x02, (byte) 0x17, (byte) 0x69, (byte) 0x90, (byte) 0x65, (byte) 0x1e,
-            (byte) 0x87, (byte) 0xf1, (byte) 0x3d, (byte) 0x17, (byte) 0xb6, (byte) 0xf4,
-            (byte) 0x31, (byte) 0x94, (byte) 0x86, (byte) 0x76, (byte) 0x55, (byte) 0xf7,
-            (byte) 0xcc, (byte) 0xba, (byte) 0xa1, (byte) 0x44, (byte) 0x03, (byte) 0x42,
-            (byte) 0x00, (byte) 0x04, (byte) 0xd9, (byte) 0xcf, (byte) 0xe7, (byte) 0x9b,
-            (byte) 0x23, (byte) 0xc8, (byte) 0xa3, (byte) 0xb8, (byte) 0x33, (byte) 0x14,
-            (byte) 0xa4, (byte) 0x4d, (byte) 0x75, (byte) 0x90, (byte) 0xf3, (byte) 0xcd,
-            (byte) 0x43, (byte) 0xe5, (byte) 0x1b, (byte) 0x05, (byte) 0x1d, (byte) 0xf3,
-            (byte) 0xd0, (byte) 0xa3, (byte) 0xb7, (byte) 0x32, (byte) 0x5f, (byte) 0x79,
-            (byte) 0xdc, (byte) 0x88, (byte) 0xb8, (byte) 0x4d, (byte) 0xb3, (byte) 0xd1,
-            (byte) 0x6d, (byte) 0xf7, (byte) 0x75, (byte) 0xf3, (byte) 0xbf, (byte) 0x50,
-            (byte) 0xa1, (byte) 0xbc, (byte) 0x03, (byte) 0x64, (byte) 0x22, (byte) 0xe6,
-            (byte) 0x1a, (byte) 0xa1, (byte) 0xe1, (byte) 0x06, (byte) 0x68, (byte) 0x3b,
-            (byte) 0xbc, (byte) 0x9f, (byte) 0xd3, (byte) 0xae, (byte) 0x77, (byte) 0x5e,
-            (byte) 0x88, (byte) 0x0c, (byte) 0x5e, (byte) 0x0c, (byte) 0xb2, (byte) 0x38
-    };
-
-    /**
-     * Generated from above and converted with:
-     *
-     * openssl x509 -outform d -in usercert.pem | xxd -i | sed 's/0x/(byte) 0x/g'
-     */
-    private static final byte[] FAKE_EC_USER_1 = new byte[] {
-            (byte) 0x30, (byte) 0x82, (byte) 0x02, (byte) 0x51, (byte) 0x30, (byte) 0x82,
-            (byte) 0x01, (byte) 0xba, (byte) 0xa0, (byte) 0x03, (byte) 0x02, (byte) 0x01,
-            (byte) 0x02, (byte) 0x02, (byte) 0x01, (byte) 0x01, (byte) 0x30, (byte) 0x0d,
-            (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86,
-            (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01, (byte) 0x05, (byte) 0x05,
-            (byte) 0x00, (byte) 0x30, (byte) 0x45, (byte) 0x31, (byte) 0x0b, (byte) 0x30,
-            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06,
-            (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31, (byte) 0x13,
-            (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x6d,
-            (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61, (byte) 0x74,
-            (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30, (byte) 0x1f, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c, (byte) 0x18,
-            (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65, (byte) 0x72, (byte) 0x6e,
-            (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57, (byte) 0x69, (byte) 0x64,
-            (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73, (byte) 0x20, (byte) 0x50,
-            (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c, (byte) 0x74, (byte) 0x64,
-            (byte) 0x30, (byte) 0x1e, (byte) 0x17, (byte) 0x0d, (byte) 0x31, (byte) 0x33,
-            (byte) 0x30, (byte) 0x38, (byte) 0x32, (byte) 0x37, (byte) 0x31, (byte) 0x36,
-            (byte) 0x33, (byte) 0x30, (byte) 0x30, (byte) 0x38, (byte) 0x5a, (byte) 0x17,
-            (byte) 0x0d, (byte) 0x32, (byte) 0x33, (byte) 0x30, (byte) 0x38, (byte) 0x32,
-            (byte) 0x35, (byte) 0x31, (byte) 0x36, (byte) 0x33, (byte) 0x30, (byte) 0x30,
-            (byte) 0x38, (byte) 0x5a, (byte) 0x30, (byte) 0x62, (byte) 0x31, (byte) 0x0b,
-            (byte) 0x30, (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04,
-            (byte) 0x06, (byte) 0x13, (byte) 0x02, (byte) 0x41, (byte) 0x55, (byte) 0x31,
-            (byte) 0x13, (byte) 0x30, (byte) 0x11, (byte) 0x06, (byte) 0x03, (byte) 0x55,
-            (byte) 0x04, (byte) 0x08, (byte) 0x0c, (byte) 0x0a, (byte) 0x53, (byte) 0x6f,
-            (byte) 0x6d, (byte) 0x65, (byte) 0x2d, (byte) 0x53, (byte) 0x74, (byte) 0x61,
-            (byte) 0x74, (byte) 0x65, (byte) 0x31, (byte) 0x21, (byte) 0x30, (byte) 0x1f,
-            (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0a, (byte) 0x0c,
-            (byte) 0x18, (byte) 0x49, (byte) 0x6e, (byte) 0x74, (byte) 0x65, (byte) 0x72,
-            (byte) 0x6e, (byte) 0x65, (byte) 0x74, (byte) 0x20, (byte) 0x57, (byte) 0x69,
-            (byte) 0x64, (byte) 0x67, (byte) 0x69, (byte) 0x74, (byte) 0x73, (byte) 0x20,
-            (byte) 0x50, (byte) 0x74, (byte) 0x79, (byte) 0x20, (byte) 0x4c, (byte) 0x74,
-            (byte) 0x64, (byte) 0x31, (byte) 0x1b, (byte) 0x30, (byte) 0x19, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03, (byte) 0x0c, (byte) 0x12,
-            (byte) 0x73, (byte) 0x65, (byte) 0x72, (byte) 0x76, (byte) 0x65, (byte) 0x72,
-            (byte) 0x2e, (byte) 0x65, (byte) 0x78, (byte) 0x61, (byte) 0x6d, (byte) 0x70,
-            (byte) 0x6c, (byte) 0x65, (byte) 0x2e, (byte) 0x63, (byte) 0x6f, (byte) 0x6d,
-            (byte) 0x30, (byte) 0x59, (byte) 0x30, (byte) 0x13, (byte) 0x06, (byte) 0x07,
-            (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0xce, (byte) 0x3d, (byte) 0x02,
-            (byte) 0x01, (byte) 0x06, (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48,
-            (byte) 0xce, (byte) 0x3d, (byte) 0x03, (byte) 0x01, (byte) 0x07, (byte) 0x03,
-            (byte) 0x42, (byte) 0x00, (byte) 0x04, (byte) 0xd9, (byte) 0xcf, (byte) 0xe7,
-            (byte) 0x9b, (byte) 0x23, (byte) 0xc8, (byte) 0xa3, (byte) 0xb8, (byte) 0x33,
-            (byte) 0x14, (byte) 0xa4, (byte) 0x4d, (byte) 0x75, (byte) 0x90, (byte) 0xf3,
-            (byte) 0xcd, (byte) 0x43, (byte) 0xe5, (byte) 0x1b, (byte) 0x05, (byte) 0x1d,
-            (byte) 0xf3, (byte) 0xd0, (byte) 0xa3, (byte) 0xb7, (byte) 0x32, (byte) 0x5f,
-            (byte) 0x79, (byte) 0xdc, (byte) 0x88, (byte) 0xb8, (byte) 0x4d, (byte) 0xb3,
-            (byte) 0xd1, (byte) 0x6d, (byte) 0xf7, (byte) 0x75, (byte) 0xf3, (byte) 0xbf,
-            (byte) 0x50, (byte) 0xa1, (byte) 0xbc, (byte) 0x03, (byte) 0x64, (byte) 0x22,
-            (byte) 0xe6, (byte) 0x1a, (byte) 0xa1, (byte) 0xe1, (byte) 0x06, (byte) 0x68,
-            (byte) 0x3b, (byte) 0xbc, (byte) 0x9f, (byte) 0xd3, (byte) 0xae, (byte) 0x77,
-            (byte) 0x5e, (byte) 0x88, (byte) 0x0c, (byte) 0x5e, (byte) 0x0c, (byte) 0xb2,
-            (byte) 0x38, (byte) 0xa3, (byte) 0x7b, (byte) 0x30, (byte) 0x79, (byte) 0x30,
-            (byte) 0x09, (byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x13,
-            (byte) 0x04, (byte) 0x02, (byte) 0x30, (byte) 0x00, (byte) 0x30, (byte) 0x2c,
-            (byte) 0x06, (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01,
-            (byte) 0x86, (byte) 0xf8, (byte) 0x42, (byte) 0x01, (byte) 0x0d, (byte) 0x04,
-            (byte) 0x1f, (byte) 0x16, (byte) 0x1d, (byte) 0x4f, (byte) 0x70, (byte) 0x65,
-            (byte) 0x6e, (byte) 0x53, (byte) 0x53, (byte) 0x4c, (byte) 0x20, (byte) 0x47,
-            (byte) 0x65, (byte) 0x6e, (byte) 0x65, (byte) 0x72, (byte) 0x61, (byte) 0x74,
-            (byte) 0x65, (byte) 0x64, (byte) 0x20, (byte) 0x43, (byte) 0x65, (byte) 0x72,
-            (byte) 0x74, (byte) 0x69, (byte) 0x66, (byte) 0x69, (byte) 0x63, (byte) 0x61,
-            (byte) 0x74, (byte) 0x65, (byte) 0x30, (byte) 0x1d, (byte) 0x06, (byte) 0x03,
-            (byte) 0x55, (byte) 0x1d, (byte) 0x0e, (byte) 0x04, (byte) 0x16, (byte) 0x04,
-            (byte) 0x14, (byte) 0xd5, (byte) 0xc4, (byte) 0x72, (byte) 0xbd, (byte) 0xd2,
-            (byte) 0x4e, (byte) 0x90, (byte) 0x1b, (byte) 0x14, (byte) 0x32, (byte) 0xdb,
-            (byte) 0x03, (byte) 0xae, (byte) 0xfa, (byte) 0x27, (byte) 0x7d, (byte) 0x8d,
-            (byte) 0xe4, (byte) 0x80, (byte) 0x58, (byte) 0x30, (byte) 0x1f, (byte) 0x06,
-            (byte) 0x03, (byte) 0x55, (byte) 0x1d, (byte) 0x23, (byte) 0x04, (byte) 0x18,
-            (byte) 0x30, (byte) 0x16, (byte) 0x80, (byte) 0x14, (byte) 0x5f, (byte) 0x5b,
-            (byte) 0x5e, (byte) 0xac, (byte) 0x29, (byte) 0xfa, (byte) 0xa1, (byte) 0x9f,
-            (byte) 0x9e, (byte) 0xad, (byte) 0x46, (byte) 0xe1, (byte) 0xbc, (byte) 0x20,
-            (byte) 0x72, (byte) 0xcf, (byte) 0x4a, (byte) 0xd4, (byte) 0xfa, (byte) 0xe3,
-            (byte) 0x30, (byte) 0x0d, (byte) 0x06, (byte) 0x09, (byte) 0x2a, (byte) 0x86,
-            (byte) 0x48, (byte) 0x86, (byte) 0xf7, (byte) 0x0d, (byte) 0x01, (byte) 0x01,
-            (byte) 0x05, (byte) 0x05, (byte) 0x00, (byte) 0x03, (byte) 0x81, (byte) 0x81,
-            (byte) 0x00, (byte) 0x43, (byte) 0x99, (byte) 0x9f, (byte) 0x67, (byte) 0x08,
-            (byte) 0x43, (byte) 0xd5, (byte) 0x6b, (byte) 0x6f, (byte) 0xd7, (byte) 0x05,
-            (byte) 0xd6, (byte) 0x75, (byte) 0x34, (byte) 0x30, (byte) 0xca, (byte) 0x20,
-            (byte) 0x47, (byte) 0x61, (byte) 0xa1, (byte) 0x89, (byte) 0xb6, (byte) 0xf1,
-            (byte) 0x49, (byte) 0x7b, (byte) 0xd9, (byte) 0xb9, (byte) 0xe8, (byte) 0x1e,
-            (byte) 0x29, (byte) 0x74, (byte) 0x0a, (byte) 0x67, (byte) 0xc0, (byte) 0x7d,
-            (byte) 0xb8, (byte) 0xe6, (byte) 0x39, (byte) 0xa8, (byte) 0x5e, (byte) 0xc3,
-            (byte) 0xb0, (byte) 0xa1, (byte) 0x30, (byte) 0x6a, (byte) 0x1f, (byte) 0x1d,
-            (byte) 0xfc, (byte) 0x11, (byte) 0x59, (byte) 0x0b, (byte) 0xb9, (byte) 0xad,
-            (byte) 0x3a, (byte) 0x4e, (byte) 0x50, (byte) 0x0a, (byte) 0x61, (byte) 0xdb,
-            (byte) 0x75, (byte) 0x6b, (byte) 0xe5, (byte) 0x3f, (byte) 0x8d, (byte) 0xde,
-            (byte) 0x28, (byte) 0x68, (byte) 0xb1, (byte) 0x29, (byte) 0x9a, (byte) 0x18,
-            (byte) 0x8a, (byte) 0xfc, (byte) 0x3f, (byte) 0x13, (byte) 0x93, (byte) 0x29,
-            (byte) 0xed, (byte) 0x22, (byte) 0x7c, (byte) 0xb4, (byte) 0x50, (byte) 0xd5,
-            (byte) 0x4d, (byte) 0x32, (byte) 0x4d, (byte) 0x42, (byte) 0x2b, (byte) 0x29,
-            (byte) 0x97, (byte) 0x86, (byte) 0xc0, (byte) 0x01, (byte) 0x00, (byte) 0x25,
-            (byte) 0xf6, (byte) 0xd3, (byte) 0x2a, (byte) 0xd8, (byte) 0xda, (byte) 0x13,
-            (byte) 0x94, (byte) 0x12, (byte) 0x78, (byte) 0x14, (byte) 0x0b, (byte) 0x51,
-            (byte) 0xc0, (byte) 0x45, (byte) 0xb4, (byte) 0x02, (byte) 0x37, (byte) 0x98,
-            (byte) 0x42, (byte) 0x3c, (byte) 0xcb, (byte) 0x2e, (byte) 0xe4, (byte) 0x38,
-            (byte) 0x69, (byte) 0x1b, (byte) 0x72, (byte) 0xf0, (byte) 0xaa, (byte) 0x89,
-            (byte) 0x7e, (byte) 0xde, (byte) 0xb2
-    };
-
-    /**
-     * The amount of time to allow before and after expected time for variance
-     * in timing tests.
-     */
-    private static final long SLOP_TIME_MILLIS = 15000L;
-
-    @Override
-    protected void setUp() throws Exception {
-        mAndroidKeyStore = android.security.KeyStore.getInstance();
-
-        assertTrue(mAndroidKeyStore.reset());
-        assertFalse(mAndroidKeyStore.isUnlocked());
-
-        mKeyStore = java.security.KeyStore.getInstance("AndroidKeyStore");
-    }
-
-    private void setupPassword() {
-        assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111"));
-        assertTrue(mAndroidKeyStore.isUnlocked());
-
-        assertEquals(0, mAndroidKeyStore.list("").length);
-    }
-
-    private void assertAliases(final String[] expectedAliases) throws KeyStoreException {
-        final Enumeration<String> aliases = mKeyStore.aliases();
-        int count = 0;
-
-        final Set<String> expectedSet = new HashSet<String>();
-        expectedSet.addAll(Arrays.asList(expectedAliases));
-
-        while (aliases.hasMoreElements()) {
-            count++;
-            final String alias = aliases.nextElement();
-            assertTrue("The alias should be in the expected set", expectedSet.contains(alias));
-            expectedSet.remove(alias);
-        }
-        assertTrue("The expected set and actual set should be exactly equal", expectedSet.isEmpty());
-        assertEquals("There should be the correct number of keystore entries",
-                expectedAliases.length, count);
-    }
-
-    public void testKeyStore_Aliases_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertAliases(new String[] {});
-
-        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED,
-                null));
-
-        assertAliases(new String[] { TEST_ALIAS_1 });
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 });
-    }
-
-    public void testKeyStore_Aliases_NotInitialized_Encrypted_Failure() throws Exception {
-        setupPassword();
-
-        try {
-            mKeyStore.aliases();
-            fail("KeyStore should throw exception when not initialized");
-        } catch (KeyStoreException success) {
-        }
-    }
-
-    public void testKeyStore_ContainsAliases_PrivateAndCA_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertAliases(new String[] {});
-
-        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED,
-                null));
-
-        assertTrue("Should contain generated private key", mKeyStore.containsAlias(TEST_ALIAS_1));
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertTrue("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_2));
-
-        assertFalse("Should not contain unadded certificate alias",
-                mKeyStore.containsAlias(TEST_ALIAS_3));
-    }
-
-    public void testKeyStore_ContainsAliases_CAOnly_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertTrue("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_2));
-    }
-
-    public void testKeyStore_ContainsAliases_NonExistent_Encrypted_Failure() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertFalse("Should contain added CA certificate", mKeyStore.containsAlias(TEST_ALIAS_1));
-    }
-
-    public void testKeyStore_DeleteEntry_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        // TEST_ALIAS_1
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        // TEST_ALIAS_2
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        // TEST_ALIAS_3
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_3, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2, TEST_ALIAS_3 });
-
-        mKeyStore.deleteEntry(TEST_ALIAS_1);
-
-        assertAliases(new String[] { TEST_ALIAS_2, TEST_ALIAS_3 });
-
-        mKeyStore.deleteEntry(TEST_ALIAS_3);
-
-        assertAliases(new String[] { TEST_ALIAS_2 });
-
-        mKeyStore.deleteEntry(TEST_ALIAS_2);
-
-        assertAliases(new String[] { });
-    }
-
-    public void testKeyStore_DeleteEntry_EmptyStore_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        // Should not throw when a non-existent entry is requested for delete.
-        mKeyStore.deleteEntry(TEST_ALIAS_1);
-    }
-
-    public void testKeyStore_DeleteEntry_NonExistent_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        // TEST_ALIAS_1
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        // Should not throw when a non-existent entry is requested for delete.
-        mKeyStore.deleteEntry(TEST_ALIAS_2);
-    }
-
-    public void testKeyStore_GetCertificate_Single_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertAliases(new String[] { TEST_ALIAS_1 });
-
-        assertNull("Certificate should not exist in keystore",
-                mKeyStore.getCertificate(TEST_ALIAS_2));
-
-        Certificate retrieved = mKeyStore.getCertificate(TEST_ALIAS_1);
-
-        assertNotNull("Retrieved certificate should not be null", retrieved);
-
-        CertificateFactory f = CertificateFactory.getInstance("X.509");
-        Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        assertEquals("Actual and retrieved certificates should be the same", actual, retrieved);
-    }
-
-    public void testKeyStore_GetCertificate_NonExist_Encrypted_Failure() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertNull("Certificate should not exist in keystore",
-                mKeyStore.getCertificate(TEST_ALIAS_1));
-    }
-
-    public void testKeyStore_GetCertificateAlias_CAEntry_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        CertificateFactory f = CertificateFactory.getInstance("X.509");
-        Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        assertEquals("Stored certificate alias should be found", TEST_ALIAS_1,
-                mKeyStore.getCertificateAlias(actual));
-    }
-
-    public void testKeyStore_GetCertificateAlias_PrivateKeyEntry_Encrypted_Success()
-            throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        CertificateFactory f = CertificateFactory.getInstance("X.509");
-        Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-
-        assertEquals("Stored certificate alias should be found", TEST_ALIAS_1,
-                mKeyStore.getCertificateAlias(actual));
-    }
-
-    public void testKeyStore_GetCertificateAlias_CAEntry_WithPrivateKeyUsingCA_Encrypted_Success()
-            throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        // Insert TrustedCertificateEntry with CA name
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        // Insert PrivateKeyEntry that uses the same CA
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        CertificateFactory f = CertificateFactory.getInstance("X.509");
-        Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        assertEquals("Stored certificate alias should be found", TEST_ALIAS_2,
-                mKeyStore.getCertificateAlias(actual));
-    }
-
-    public void testKeyStore_GetCertificateAlias_NonExist_Empty_Encrypted_Failure()
-            throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        CertificateFactory f = CertificateFactory.getInstance("X.509");
-        Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        assertNull("Stored certificate alias should not be found",
-                mKeyStore.getCertificateAlias(actual));
-    }
-
-    public void testKeyStore_GetCertificateAlias_NonExist_Encrypted_Failure() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        CertificateFactory f = CertificateFactory.getInstance("X.509");
-        Certificate userCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-
-        assertNull("Stored certificate alias should be found",
-                mKeyStore.getCertificateAlias(userCert));
-    }
-
-    public void testKeyStore_GetCertificateChain_SingleLength_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        CertificateFactory cf = CertificateFactory.getInstance("X.509");
-        Certificate[] expected = new Certificate[2];
-        expected[0] = cf.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-        expected[1] = cf.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        Certificate[] actual = mKeyStore.getCertificateChain(TEST_ALIAS_1);
-
-        assertNotNull("Returned certificate chain should not be null", actual);
-        assertEquals("Returned certificate chain should be correct size", expected.length,
-                actual.length);
-        assertEquals("First certificate should be user certificate", expected[0], actual[0]);
-        assertEquals("Second certificate should be CA certificate", expected[1], actual[1]);
-
-        // Negative test when keystore is populated.
-        assertNull("Stored certificate alias should not be found",
-                mKeyStore.getCertificateChain(TEST_ALIAS_2));
-    }
-
-    public void testKeyStore_GetCertificateChain_NonExist_Encrypted_Failure() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertNull("Stored certificate alias should not be found",
-                mKeyStore.getCertificateChain(TEST_ALIAS_1));
-    }
-
-    public void testKeyStore_GetCreationDate_PrivateKeyEntry_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        Date now = new Date();
-        Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1);
-
-        Date expectedAfter = new Date(now.getTime() - SLOP_TIME_MILLIS);
-        Date expectedBefore = new Date(now.getTime() + SLOP_TIME_MILLIS);
-
-        assertTrue("Time should be close to current time", actual.before(expectedBefore));
-        assertTrue("Time should be close to current time", actual.after(expectedAfter));
-    }
-
-    public void testKeyStore_GetCreationDate_PrivateKeyEntry_Unencrypted_Success() throws Exception {
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-
-        Date now = new Date();
-        Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1);
-
-        Date expectedAfter = new Date(now.getTime() - SLOP_TIME_MILLIS);
-        Date expectedBefore = new Date(now.getTime() + SLOP_TIME_MILLIS);
-
-        assertTrue("Time should be close to current time", actual.before(expectedBefore));
-        assertTrue("Time should be close to current time", actual.after(expectedAfter));
-    }
-
-    public void testKeyStore_GetCreationDate_CAEntry_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        Date now = new Date();
-        Date actual = mKeyStore.getCreationDate(TEST_ALIAS_1);
-        assertNotNull("Certificate should be found", actual);
-
-        Date expectedAfter = new Date(now.getTime() - SLOP_TIME_MILLIS);
-        Date expectedBefore = new Date(now.getTime() + SLOP_TIME_MILLIS);
-
-        assertTrue("Time should be close to current time", actual.before(expectedBefore));
-        assertTrue("Time should be close to current time", actual.after(expectedAfter));
-    }
-
-    public void testKeyStore_GetEntry_NullParams_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-        assertNotNull("Entry should exist", entry);
-
-        assertTrue("Should be a PrivateKeyEntry", entry instanceof PrivateKeyEntry);
-
-        PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
-
-        assertPrivateKeyEntryEquals(keyEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1,
-                FAKE_RSA_CA_1);
-    }
-
-    public void testKeyStore_GetEntry_EC_NullParams_Unencrypted_Success() throws Exception {
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_EC_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
-                FAKE_EC_USER_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_EC_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-
-        Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-        assertNotNull("Entry should exist", entry);
-
-        assertTrue("Should be a PrivateKeyEntry", entry instanceof PrivateKeyEntry);
-
-        PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
-
-        assertPrivateKeyEntryEquals(keyEntry, "EC", FAKE_EC_KEY_1, FAKE_EC_USER_1, FAKE_EC_CA_1);
-    }
-
-    public void testKeyStore_GetEntry_RSA_NullParams_Unencrypted_Success() throws Exception {
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
-                FAKE_RSA_USER_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-
-        Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-        assertNotNull("Entry should exist", entry);
-
-        assertTrue("Should be a PrivateKeyEntry", entry instanceof PrivateKeyEntry);
-
-        PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
-
-        assertPrivateKeyEntryEquals(keyEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1,
-                FAKE_RSA_CA_1);
-    }
-
-    @SuppressWarnings("unchecked")
-    private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, String keyType, byte[] key,
-            byte[] cert, byte[] ca) throws Exception {
-        KeyFactory keyFact = KeyFactory.getInstance(keyType);
-        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(key));
-
-        CertificateFactory certFact = CertificateFactory.getInstance("X.509");
-        Certificate expectedCert = certFact.generateCertificate(new ByteArrayInputStream(cert));
-
-        final Collection<Certificate> expectedChain;
-        if (ca != null) {
-            expectedChain = (Collection<Certificate>) certFact
-                    .generateCertificates(new ByteArrayInputStream(ca));
-        } else {
-            expectedChain = null;
-        }
-
-        assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, expectedChain);
-    }
-
-    private void assertPrivateKeyEntryEquals(PrivateKeyEntry keyEntry, PrivateKey expectedKey,
-            Certificate expectedCert, Collection<Certificate> expectedChain) throws Exception {
-        if (expectedKey instanceof ECKey) {
-            assertEquals("Returned PrivateKey should be what we inserted",
-                    ((ECKey) expectedKey).getParams().getCurve(),
-                    ((ECKey) keyEntry.getCertificate().getPublicKey()).getParams().getCurve());
-        } else if (expectedKey instanceof RSAKey) {
-            assertEquals("Returned PrivateKey should be what we inserted",
-                    ((RSAKey) expectedKey).getModulus(),
-                    ((RSAKey) keyEntry.getPrivateKey()).getModulus());
-        }
-
-        assertEquals("Returned Certificate should be what we inserted", expectedCert,
-                keyEntry.getCertificate());
-
-        Certificate[] actualChain = keyEntry.getCertificateChain();
-
-        assertEquals("First certificate in chain should be user cert", expectedCert, actualChain[0]);
-
-        if (expectedChain == null) {
-            assertEquals("Certificate chain should not include CAs", 1, actualChain.length);
-        } else {
-            int i = 1;
-            final Iterator<Certificate> it = expectedChain.iterator();
-            while (it.hasNext()) {
-                assertEquals("CA chain certificate should equal what we put in", it.next(),
-                        actualChain[i++]);
-            }
-        }
-    }
-
-    public void testKeyStore_GetEntry_Nonexistent_NullParams_Encrypted_Failure() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertNull("A non-existent entry should return null",
-                mKeyStore.getEntry(TEST_ALIAS_1, null));
-    }
-
-    public void testKeyStore_GetEntry_Nonexistent_NullParams_Unencrypted_Failure() throws Exception {
-        mKeyStore.load(null, null);
-
-        assertNull("A non-existent entry should return null",
-                mKeyStore.getEntry(TEST_ALIAS_1, null));
-    }
-
-    public void testKeyStore_GetKey_NoPassword_Encrypted_Success() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
-        assertNotNull("Key should exist", key);
-
-        assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
-        assertTrue("Should be a RSAKey", key instanceof RSAKey);
-
-        KeyFactory keyFact = KeyFactory.getInstance("RSA");
-        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-
-        assertEquals("Inserted key should be same as retrieved key",
-                ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus());
-    }
-
-    public void testKeyStore_GetKey_NoPassword_Unencrypted_Success() throws Exception {
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_NONE));
-
-        Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
-        assertNotNull("Key should exist", key);
-
-        assertTrue("Should be a PrivateKey", key instanceof PrivateKey);
-        assertTrue("Should be a RSAKey", key instanceof RSAKey);
-
-        KeyFactory keyFact = KeyFactory.getInstance("RSA");
-        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-
-        assertEquals("Inserted key should be same as retrieved key",
-                ((RSAKey) expectedKey).getModulus(), ((RSAKey) key).getModulus());
-    }
-
-    public void testKeyStore_GetKey_Certificate_Encrypted_Failure() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertNull("Certificate entries should return null", mKeyStore.getKey(TEST_ALIAS_1, null));
-    }
-
-    public void testKeyStore_GetKey_NonExistent_Encrypted_Failure() throws Exception {
-        setupPassword();
-
-        mKeyStore.load(null, null);
-
-        assertNull("A non-existent entry should return null", mKeyStore.getKey(TEST_ALIAS_1, null));
-    }
-
-    public void testKeyStore_GetProvider_Encrypted_Success() throws Exception {
-        assertEquals(AndroidKeyStoreProvider.PROVIDER_NAME, mKeyStore.getProvider().getName());
-        setupPassword();
-        assertEquals(AndroidKeyStoreProvider.PROVIDER_NAME, mKeyStore.getProvider().getName());
-    }
-
-    public void testKeyStore_GetType_Encrypted_Success() throws Exception {
-        assertEquals(AndroidKeyStoreSpi.NAME, mKeyStore.getType());
-        setupPassword();
-        assertEquals(AndroidKeyStoreSpi.NAME, mKeyStore.getType());
-    }
-
-    public void testKeyStore_IsCertificateEntry_CA_Encrypted_Success() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertTrue("Should return true for CA certificate",
-                mKeyStore.isCertificateEntry(TEST_ALIAS_1));
-    }
-
-    public void testKeyStore_IsCertificateEntry_PrivateKey_Encrypted_Failure() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertFalse("Should return false for PrivateKeyEntry",
-                mKeyStore.isCertificateEntry(TEST_ALIAS_1));
-    }
-
-    public void testKeyStore_IsCertificateEntry_NonExist_Encrypted_Failure() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        assertFalse("Should return false for non-existent entry",
-                mKeyStore.isCertificateEntry(TEST_ALIAS_1));
-    }
-
-    public void testKeyStore_IsCertificateEntry_NonExist_Unencrypted_Failure() throws Exception {
-        mKeyStore.load(null, null);
-
-        assertFalse("Should return false for non-existent entry",
-                mKeyStore.isCertificateEntry(TEST_ALIAS_1));
-    }
-
-    public void testKeyStore_IsKeyEntry_PrivateKey_Encrypted_Success() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertTrue("Should return true for PrivateKeyEntry", mKeyStore.isKeyEntry(TEST_ALIAS_1));
-    }
-
-    public void testKeyStore_IsKeyEntry_CA_Encrypted_Failure() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertFalse("Should return false for CA certificate", mKeyStore.isKeyEntry(TEST_ALIAS_1));
-    }
-
-    public void testKeyStore_IsKeyEntry_NonExist_Encrypted_Failure() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        assertFalse("Should return false for non-existent entry",
-                mKeyStore.isKeyEntry(TEST_ALIAS_1));
-    }
-
-    public void testKeyStore_SetCertificate_CA_Encrypted_Success() throws Exception {
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-        final Certificate actual = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        mKeyStore.setCertificateEntry(TEST_ALIAS_1, actual);
-        assertAliases(new String[] { TEST_ALIAS_1 });
-
-        Certificate retrieved = mKeyStore.getCertificate(TEST_ALIAS_1);
-
-        assertEquals("Retrieved certificate should be the same as the one inserted", actual,
-                retrieved);
-    }
-
-    public void testKeyStore_SetCertificate_CAExists_Overwrite_Encrypted_Success() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertAliases(new String[] { TEST_ALIAS_1 });
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-        final Certificate cert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        // TODO have separate FAKE_CA for second test
-        mKeyStore.setCertificateEntry(TEST_ALIAS_1, cert);
-
-        assertAliases(new String[] { TEST_ALIAS_1 });
-    }
-
-    public void testKeyStore_SetCertificate_PrivateKeyExists_Encrypted_Failure() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.importKey(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1,
-                FAKE_RSA_KEY_1, KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_USER_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertAliases(new String[] { TEST_ALIAS_1 });
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-        final Certificate cert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        try {
-            mKeyStore.setCertificateEntry(TEST_ALIAS_1, cert);
-            fail("Should throw when trying to overwrite a PrivateKey entry with a Certificate");
-        } catch (KeyStoreException success) {
-        }
-    }
-
-    public void testKeyStore_SetEntry_PrivateKeyEntry_Encrypted_Success() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        KeyFactory keyFact = KeyFactory.getInstance("RSA");
-        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        final Certificate[] expectedChain = new Certificate[2];
-        expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-        expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain);
-
-        mKeyStore.setEntry(TEST_ALIAS_1, expected, null);
-
-        Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-        assertNotNull("Retrieved entry should exist", actualEntry);
-
-        assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                actualEntry instanceof PrivateKeyEntry);
-
-        PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
-
-        assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, FAKE_RSA_CA_1);
-    }
-
-    public void testKeyStore_SetEntry_PrivateKeyEntry_EC_Unencrypted_Success() throws Exception {
-        mKeyStore.load(null, null);
-
-        KeyFactory keyFact = KeyFactory.getInstance("EC");
-        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_EC_KEY_1));
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        final Certificate[] expectedChain = new Certificate[2];
-        expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_EC_USER_1));
-        expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_EC_CA_1));
-
-        PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain);
-
-        mKeyStore.setEntry(TEST_ALIAS_1, expected, null);
-
-        Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-        assertNotNull("Retrieved entry should exist", actualEntry);
-
-        assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                actualEntry instanceof PrivateKeyEntry);
-
-        PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
-
-        assertPrivateKeyEntryEquals(actual, "EC", FAKE_EC_KEY_1, FAKE_EC_USER_1, FAKE_EC_CA_1);
-    }
-
-    public void testKeyStore_SetEntry_PrivateKeyEntry_RSA_Unencrypted_Success() throws Exception {
-        mKeyStore.load(null, null);
-
-        KeyFactory keyFact = KeyFactory.getInstance("RSA");
-        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        final Certificate[] expectedChain = new Certificate[2];
-        expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-        expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain);
-
-        mKeyStore.setEntry(TEST_ALIAS_1, expected, null);
-
-        Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-        assertNotNull("Retrieved entry should exist", actualEntry);
-
-        assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                actualEntry instanceof PrivateKeyEntry);
-
-        PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
-
-        assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, FAKE_RSA_CA_1);
-    }
-
-    public void testKeyStore_SetEntry_PrivateKeyEntry_Params_Unencrypted_Failure() throws Exception {
-        mKeyStore.load(null, null);
-
-        KeyFactory keyFact = KeyFactory.getInstance("RSA");
-        PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        final Certificate[] expectedChain = new Certificate[2];
-        expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-        expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        PrivateKeyEntry entry = new PrivateKeyEntry(expectedKey, expectedChain);
-
-        try {
-            mKeyStore.setEntry(TEST_ALIAS_1, entry,
-                    new KeyStoreParameter.Builder(getContext())
-                    .setEncryptionRequired(true)
-                    .build());
-            fail("Shouldn't be able to insert encrypted entry when KeyStore uninitialized");
-        } catch (KeyStoreException expected) {
-        }
-
-        assertNull(mKeyStore.getEntry(TEST_ALIAS_1, null));
-    }
-
-    public void
-            testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_PrivateKeyEntry_Encrypted_Success()
-            throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        final KeyFactory keyFact = KeyFactory.getInstance("RSA");
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        // Start with PrivateKeyEntry
-        {
-            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-
-            final Certificate[] expectedChain = new Certificate[2];
-            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-            expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-            PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain);
-
-            mKeyStore.setEntry(TEST_ALIAS_1, expected, null);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-
-            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                    actualEntry instanceof PrivateKeyEntry);
-
-            PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
-
-            assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1,
-                    FAKE_RSA_CA_1);
-        }
-
-        // TODO make entirely new test vector for the overwrite
-        // Replace with PrivateKeyEntry
-        {
-            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-
-            final Certificate[] expectedChain = new Certificate[2];
-            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-            expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-            PrivateKeyEntry expected = new PrivateKeyEntry(expectedKey, expectedChain);
-
-            mKeyStore.setEntry(TEST_ALIAS_1, expected, null);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-
-            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                    actualEntry instanceof PrivateKeyEntry);
-
-            PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
-
-            assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1,
-                    FAKE_RSA_CA_1);
-        }
-    }
-
-    public void testKeyStore_SetEntry_CAEntry_Overwrites_PrivateKeyEntry_Encrypted_Success()
-            throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        // Start with TrustedCertificateEntry
-        {
-            final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-            TrustedCertificateEntry expectedCertEntry = new TrustedCertificateEntry(caCert);
-            mKeyStore.setEntry(TEST_ALIAS_1, expectedCertEntry, null);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-            assertTrue("Retrieved entry should be of type TrustedCertificateEntry",
-                    actualEntry instanceof TrustedCertificateEntry);
-            TrustedCertificateEntry actualCertEntry = (TrustedCertificateEntry) actualEntry;
-            assertEquals("Stored and retrieved certificates should be the same",
-                    expectedCertEntry.getTrustedCertificate(),
-                    actualCertEntry.getTrustedCertificate());
-        }
-
-        // Replace with PrivateKeyEntry
-        {
-            KeyFactory keyFact = KeyFactory.getInstance("RSA");
-            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-            final Certificate[] expectedChain = new Certificate[2];
-            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-            expectedChain[1] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-            PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain);
-
-            mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                    actualEntry instanceof PrivateKeyEntry);
-
-            PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry;
-            assertPrivateKeyEntryEquals(actualPrivEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1,
-                    FAKE_RSA_CA_1);
-        }
-    }
-
-    public void testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_CAEntry_Encrypted_Success()
-            throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        // Start with PrivateKeyEntry
-        {
-            KeyFactory keyFact = KeyFactory.getInstance("RSA");
-            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-            final Certificate[] expectedChain = new Certificate[2];
-            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-            expectedChain[1] = caCert;
-
-            PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain);
-
-            mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                    actualEntry instanceof PrivateKeyEntry);
-
-            PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry;
-            assertPrivateKeyEntryEquals(actualPrivEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1,
-                    FAKE_RSA_CA_1);
-        }
-
-        // Replace with TrustedCertificateEntry
-        {
-            TrustedCertificateEntry expectedCertEntry = new TrustedCertificateEntry(caCert);
-            mKeyStore.setEntry(TEST_ALIAS_1, expectedCertEntry, null);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-            assertTrue("Retrieved entry should be of type TrustedCertificateEntry",
-                    actualEntry instanceof TrustedCertificateEntry);
-            TrustedCertificateEntry actualCertEntry = (TrustedCertificateEntry) actualEntry;
-            assertEquals("Stored and retrieved certificates should be the same",
-                    expectedCertEntry.getTrustedCertificate(),
-                    actualCertEntry.getTrustedCertificate());
-        }
-    }
-
-    public
-            void
-            testKeyStore_SetEntry_PrivateKeyEntry_Overwrites_ShortPrivateKeyEntry_Encrypted_Success()
-            throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        // Start with PrivateKeyEntry
-        {
-            KeyFactory keyFact = KeyFactory.getInstance("RSA");
-            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-            final Certificate[] expectedChain = new Certificate[2];
-            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-            expectedChain[1] = caCert;
-
-            PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain);
-
-            mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                    actualEntry instanceof PrivateKeyEntry);
-
-            PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry;
-            assertPrivateKeyEntryEquals(actualPrivEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1,
-                    FAKE_RSA_CA_1);
-        }
-
-        // Replace with PrivateKeyEntry that has no chain
-        {
-            KeyFactory keyFact = KeyFactory.getInstance("RSA");
-            PrivateKey expectedKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-            final Certificate[] expectedChain = new Certificate[1];
-            expectedChain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-
-            PrivateKeyEntry expectedPrivEntry = new PrivateKeyEntry(expectedKey, expectedChain);
-
-            mKeyStore.setEntry(TEST_ALIAS_1, expectedPrivEntry, null);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                    actualEntry instanceof PrivateKeyEntry);
-
-            PrivateKeyEntry actualPrivEntry = (PrivateKeyEntry) actualEntry;
-            assertPrivateKeyEntryEquals(actualPrivEntry, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1,
-                    null);
-        }
-    }
-
-    public void testKeyStore_SetEntry_CAEntry_Overwrites_CAEntry_Encrypted_Success()
-            throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        // Insert TrustedCertificateEntry
-        {
-            final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-            TrustedCertificateEntry expectedCertEntry = new TrustedCertificateEntry(caCert);
-            mKeyStore.setEntry(TEST_ALIAS_1, expectedCertEntry, null);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-            assertTrue("Retrieved entry should be of type TrustedCertificateEntry",
-                    actualEntry instanceof TrustedCertificateEntry);
-            TrustedCertificateEntry actualCertEntry = (TrustedCertificateEntry) actualEntry;
-            assertEquals("Stored and retrieved certificates should be the same",
-                    expectedCertEntry.getTrustedCertificate(),
-                    actualCertEntry.getTrustedCertificate());
-        }
-
-        // Replace with TrustedCertificateEntry of USER
-        {
-            final Certificate userCert = f
-                    .generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-
-            TrustedCertificateEntry expectedUserEntry = new TrustedCertificateEntry(userCert);
-            mKeyStore.setEntry(TEST_ALIAS_1, expectedUserEntry, null);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-            assertTrue("Retrieved entry should be of type TrustedCertificateEntry",
-                    actualEntry instanceof TrustedCertificateEntry);
-            TrustedCertificateEntry actualUserEntry = (TrustedCertificateEntry) actualEntry;
-            assertEquals("Stored and retrieved certificates should be the same",
-                    expectedUserEntry.getTrustedCertificate(),
-                    actualUserEntry.getTrustedCertificate());
-        }
-    }
-
-    public void testKeyStore_SetKeyEntry_ProtectedKey_Encrypted_Failure() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        KeyFactory keyFact = KeyFactory.getInstance("RSA");
-        PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-        final Certificate[] chain = new Certificate[2];
-        chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-        chain[1] = caCert;
-
-        try {
-            mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, "foo".toCharArray(), chain);
-            fail("Should fail when a password is specified");
-        } catch (KeyStoreException success) {
-        }
-    }
-
-    public void testKeyStore_SetKeyEntry_Encrypted_Success() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        KeyFactory keyFact = KeyFactory.getInstance("RSA");
-        PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-        final Certificate[] chain = new Certificate[2];
-        chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-        chain[1] = caCert;
-
-        mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, null, chain);
-
-        Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-        assertNotNull("Retrieved entry should exist", actualEntry);
-
-        assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                actualEntry instanceof PrivateKeyEntry);
-
-        PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
-
-        assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1, FAKE_RSA_CA_1);
-    }
-
-    public void testKeyStore_SetKeyEntry_Replaced_Encrypted_Success() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        final CertificateFactory f = CertificateFactory.getInstance("X.509");
-
-        final Certificate caCert = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_CA_1));
-
-        // Insert initial key
-        {
-            KeyFactory keyFact = KeyFactory.getInstance("RSA");
-            PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-            final Certificate[] chain = new Certificate[2];
-            chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-            chain[1] = caCert;
-
-            mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, null, chain);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-
-            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                    actualEntry instanceof PrivateKeyEntry);
-
-            PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
-
-            assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1,
-                    FAKE_RSA_CA_1);
-        }
-
-        // TODO make a separate key
-        // Replace key
-        {
-            KeyFactory keyFact = KeyFactory.getInstance("RSA");
-            PrivateKey privKey = keyFact.generatePrivate(new PKCS8EncodedKeySpec(FAKE_RSA_KEY_1));
-            final Certificate[] chain = new Certificate[2];
-            chain[0] = f.generateCertificate(new ByteArrayInputStream(FAKE_RSA_USER_1));
-            chain[1] = caCert;
-
-            mKeyStore.setKeyEntry(TEST_ALIAS_1, privKey, null, chain);
-
-            Entry actualEntry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-            assertNotNull("Retrieved entry should exist", actualEntry);
-
-            assertTrue("Retrieved entry should be of type PrivateKeyEntry",
-                    actualEntry instanceof PrivateKeyEntry);
-
-            PrivateKeyEntry actual = (PrivateKeyEntry) actualEntry;
-
-            assertPrivateKeyEntryEquals(actual, "RSA", FAKE_RSA_KEY_1, FAKE_RSA_USER_1,
-                    FAKE_RSA_CA_1);
-        }
-    }
-
-    @SuppressWarnings("deprecation")
-    private static X509Certificate generateCertificate(android.security.KeyStore keyStore,
-            String alias, BigInteger serialNumber, X500Principal subjectDN, Date notBefore,
-            Date notAfter) throws Exception {
-        final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
-
-        KeyPair keyPair = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
-                keyStore, privateKeyAlias, KeyStore.UID_SELF);
-
-        final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
-        certGen.setPublicKey(keyPair.getPublic());
-        certGen.setSerialNumber(serialNumber);
-        certGen.setSubjectDN(subjectDN);
-        certGen.setIssuerDN(subjectDN);
-        certGen.setNotBefore(notBefore);
-        certGen.setNotAfter(notAfter);
-        certGen.setSignatureAlgorithm("sha1WithRSA");
-
-        final X509Certificate cert = certGen.generate(keyPair.getPrivate());
-
-        return cert;
-    }
-
-    public void testKeyStore_SetKeyEntry_ReplacedChain_Encrypted_Success() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        // Create key #1
-        {
-            final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
-            assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
-                    NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null));
-
-            Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
-
-            assertTrue(key instanceof PrivateKey);
-
-            PrivateKey expectedKey = (PrivateKey) key;
-
-            X509Certificate expectedCert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
-                    TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
-
-            assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
-                    expectedCert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-            Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-
-            assertTrue(entry instanceof PrivateKeyEntry);
-
-            PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
-
-            assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, null);
-        }
-
-        // Replace key #1 with new chain
-        {
-            Key key = mKeyStore.getKey(TEST_ALIAS_1, null);
-
-            assertTrue(key instanceof PrivateKey);
-
-            PrivateKey expectedKey = (PrivateKey) key;
-
-            X509Certificate expectedCert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
-                    TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
-
-            mKeyStore.setKeyEntry(TEST_ALIAS_1, expectedKey, null,
-                    new Certificate[] { expectedCert });
-
-            Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-
-            assertTrue(entry instanceof PrivateKeyEntry);
-
-            PrivateKeyEntry keyEntry = (PrivateKeyEntry) entry;
-
-            assertPrivateKeyEntryEquals(keyEntry, expectedKey, expectedCert, null);
-        }
-    }
-
-    public void testKeyStore_SetKeyEntry_ReplacedChain_DifferentPrivateKey_Encrypted_Failure()
-            throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        // Create key #1
-        {
-            final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
-            assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
-                    NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null));
-
-            X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1,
-                    TEST_SERIAL_1, TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
-
-            assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
-                    cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        }
-
-        // Create key #2
-        {
-            final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_2;
-            assertTrue(mAndroidKeyStore.generate(privateKeyAlias, KeyStore.UID_SELF,
-                    NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED, null));
-
-            X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2,
-                    TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
-
-            assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_2,
-                    cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-        }
-
-        // Replace key #1 with key #2
-        {
-            Key key1 = mKeyStore.getKey(TEST_ALIAS_2, null);
-
-            X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_2,
-                    TEST_SERIAL_2, TEST_DN_2, NOW, NOW_PLUS_10_YEARS);
-
-            try {
-                mKeyStore.setKeyEntry(TEST_ALIAS_1, key1, null, new Certificate[] { cert });
-                fail("Should not allow setting of KeyEntry with wrong PrivaetKey");
-            } catch (KeyStoreException success) {
-            }
-        }
-    }
-
-    public void testKeyStore_SetKeyEntry_ReplacedChain_UnencryptedToEncrypted_Failure()
-            throws Exception {
-        mKeyStore.load(null, null);
-
-        // Create key #1
-        {
-            final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
-            assertTrue(mAndroidKeyStore.generate(privateKeyAlias,
-                    android.security.KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024,
-                    android.security.KeyStore.FLAG_NONE, null));
-
-            X509Certificate cert =
-                    generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, TEST_SERIAL_1, TEST_DN_1,
-                            NOW, NOW_PLUS_10_YEARS);
-
-            assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
-                    cert.getEncoded(), android.security.KeyStore.UID_SELF,
-                    android.security.KeyStore.FLAG_NONE));
-        }
-
-        // Replace with one that requires encryption
-        {
-            Entry entry = mKeyStore.getEntry(TEST_ALIAS_1, null);
-
-            try {
-                mKeyStore.setEntry(TEST_ALIAS_1, entry,
-                        new KeyStoreParameter.Builder(getContext())
-                                .setEncryptionRequired(true)
-                                .build());
-                fail("Should not allow setting of Entry without unlocked keystore");
-            } catch (KeyStoreException success) {
-            }
-
-            assertTrue(mAndroidKeyStore.onUserPasswordChanged("1111"));
-            assertTrue(mAndroidKeyStore.isUnlocked());
-
-            mKeyStore.setEntry(TEST_ALIAS_1, entry,
-                    new KeyStoreParameter.Builder(getContext())
-                            .setEncryptionRequired(true)
-                            .build());
-        }
-    }
-
-    public void testKeyStore_Size_Encrypted_Success() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_1, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertEquals("The keystore size should match expected", 1, mKeyStore.size());
-        assertAliases(new String[] { TEST_ALIAS_1 });
-
-        assertTrue(mAndroidKeyStore.put(Credentials.CA_CERTIFICATE + TEST_ALIAS_2, FAKE_RSA_CA_1,
-                KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-
-        assertEquals("The keystore size should match expected", 2, mKeyStore.size());
-        assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2 });
-
-        assertTrue(mAndroidKeyStore.generate(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3,
-                KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024, KeyStore.FLAG_ENCRYPTED,
-                null));
-
-        assertEquals("The keystore size should match expected", 3, mKeyStore.size());
-        assertAliases(new String[] { TEST_ALIAS_1, TEST_ALIAS_2, TEST_ALIAS_3 });
-
-        assertTrue(mAndroidKeyStore.delete(Credentials.CA_CERTIFICATE + TEST_ALIAS_1));
-
-        assertEquals("The keystore size should match expected", 2, mKeyStore.size());
-        assertAliases(new String[] { TEST_ALIAS_2, TEST_ALIAS_3 });
-
-        assertTrue(mAndroidKeyStore.delete(Credentials.USER_PRIVATE_KEY + TEST_ALIAS_3));
-
-        assertEquals("The keystore size should match expected", 1, mKeyStore.size());
-        assertAliases(new String[] { TEST_ALIAS_2 });
-    }
-
-    public void testKeyStore_Store_LoadStoreParam_Encrypted_Failure() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        try {
-            mKeyStore.store(null);
-            fail("Should throw UnsupportedOperationException when trying to store");
-        } catch (UnsupportedOperationException success) {
-        }
-    }
-
-    public void testKeyStore_Load_InputStreamSupplied_Encrypted_Failure() throws Exception {
-        byte[] buf = "FAKE KEYSTORE".getBytes();
-        ByteArrayInputStream is = new ByteArrayInputStream(buf);
-
-        try {
-            mKeyStore.load(is, null);
-            fail("Should throw IllegalArgumentException when InputStream is supplied");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-
-    public void testKeyStore_Load_PasswordSupplied_Encrypted_Failure() throws Exception {
-        try {
-            mKeyStore.load(null, "password".toCharArray());
-            fail("Should throw IllegalArgumentException when password is supplied");
-        } catch (IllegalArgumentException success) {
-        }
-    }
-
-    public void testKeyStore_Store_OutputStream_Encrypted_Failure() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        OutputStream sink = new ByteArrayOutputStream();
-        try {
-            mKeyStore.store(sink, null);
-            fail("Should throw UnsupportedOperationException when trying to store");
-        } catch (UnsupportedOperationException success) {
-        }
-
-        try {
-            mKeyStore.store(sink, "blah".toCharArray());
-            fail("Should throw UnsupportedOperationException when trying to store");
-        } catch (UnsupportedOperationException success) {
-        }
-    }
-
-    private void setupKey() throws Exception {
-        final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + TEST_ALIAS_1;
-        assertTrue(mAndroidKeyStore
-                .generate(privateKeyAlias, KeyStore.UID_SELF, NativeConstants.EVP_PKEY_RSA, 1024,
-                        KeyStore.FLAG_ENCRYPTED, null));
-
-        X509Certificate cert = generateCertificate(mAndroidKeyStore, TEST_ALIAS_1, TEST_SERIAL_1,
-                TEST_DN_1, NOW, NOW_PLUS_10_YEARS);
-
-        assertTrue(mAndroidKeyStore.put(Credentials.USER_CERTIFICATE + TEST_ALIAS_1,
-                cert.getEncoded(), KeyStore.UID_SELF, KeyStore.FLAG_ENCRYPTED));
-    }
-
-    public void testKeyStore_KeyOperations_Wrap_Encrypted_Success() throws Exception {
-        setupPassword();
-        mKeyStore.load(null, null);
-
-        setupKey();
-
-        // Test key usage
-        Entry e = mKeyStore.getEntry(TEST_ALIAS_1, null);
-        assertNotNull(e);
-        assertTrue(e instanceof PrivateKeyEntry);
-
-        PrivateKeyEntry privEntry = (PrivateKeyEntry) e;
-        PrivateKey privKey = privEntry.getPrivateKey();
-        assertNotNull(privKey);
-
-        PublicKey pubKey = privEntry.getCertificate().getPublicKey();
-
-        Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding");
-        c.init(Cipher.WRAP_MODE, pubKey);
-
-        byte[] expectedKey = new byte[] {
-                0x00, 0x05, (byte) 0xAA, (byte) 0x0A5, (byte) 0xFF, 0x55, 0x0A
-        };
-
-        SecretKey expectedSecret = new SecretKeySpec(expectedKey, "AES");
-
-        byte[] wrappedExpected = c.wrap(expectedSecret);
-
-        c.init(Cipher.UNWRAP_MODE, privKey);
-        SecretKey actualSecret = (SecretKey) c.unwrap(wrappedExpected, "AES", Cipher.SECRET_KEY);
-
-        assertEquals(Arrays.toString(expectedSecret.getEncoded()),
-                Arrays.toString(actualSecret.getEncoded()));
-    }
-}
diff --git a/libs/hwui/Android.bp b/libs/hwui/Android.bp
new file mode 100644
index 0000000..acf8883
--- /dev/null
+++ b/libs/hwui/Android.bp
@@ -0,0 +1,387 @@
+cc_defaults {
+    name: "hwui_defaults",
+    defaults: [
+        "hwui_static_deps",
+
+        //"hwui_bugreport_font_cache_usage",
+        //"hwui_compile_for_perf",
+
+        // Enables fine-grained GLES error checking
+        // If enabled, every GLES call is wrapped & error checked
+        // Has moderate overhead
+        //"hwui_enable_opengl-validation",
+    ],
+
+    cflags: [
+        "-DEGL_EGLEXT_PROTOTYPES",
+        "-DGL_GLEXT_PROTOTYPES",
+        "-DATRACE_TAG=ATRACE_TAG_VIEW",
+        "-DLOG_TAG=\"OpenGLRenderer\"",
+        "-Wall",
+        "-Wno-unused-parameter",
+        "-Wunreachable-code",
+        "-Werror",
+        "-fvisibility=hidden",
+
+        // GCC false-positives on this warning, and since we -Werror that's
+        // a problem
+        "-Wno-free-nonheap-object",
+
+        // clang's warning is broken, see: https://llvm.org/bugs/show_bug.cgi?id=21629
+        "-Wno-missing-braces",
+
+        // TODO: Linear blending should be enabled by default, but we are
+        // TODO: making it an opt-in while it's a work in progress
+        //"-DANDROID_ENABLE_LINEAR_BLENDING",
+    ],
+
+    include_dirs: [
+        "external/skia/include/private",
+        "external/skia/src/core",
+        "external/skia/src/effects",
+        "external/skia/src/image",
+        "external/skia/src/utils",
+    ],
+
+    product_variables: {
+        device_uses_hwc2: {
+            cflags: ["-DUSE_HWC2"],
+        },
+    },
+}
+
+cc_defaults {
+    name: "hwui_static_deps",
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libutils",
+        "libEGL",
+        "libGLESv2",
+        "libvulkan",
+        "libskia",
+        "libui",
+        "libgui",
+        "libprotobuf-cpp-full",
+        "libharfbuzz_ng",
+        "libft2",
+        "libminikin",
+        "libandroidfw",
+        "libRScpp",
+    ],
+    static_libs: [
+        "libplatformprotos",
+    ],
+}
+
+cc_defaults {
+    name: "hwui_bugreport_font_cache_usage",
+    srcs: ["font/FontCacheHistoryTracker.cpp"],
+    cflags: ["-DBUGREPORT_FONT_CACHE_USAGE"],
+}
+
+cc_defaults {
+    name: "hwui_compile_for_perf",
+    // TODO: Non-arm?
+    cflags: [
+        "-fno-omit-frame-pointer",
+        "-marm",
+        "-mapcs",
+    ],
+}
+
+cc_defaults {
+    name: "hwui_debug",
+    cflags: ["-include debug/wrap_gles.h"],
+    srcs: [
+        "debug/wrap_gles.cpp",
+        "debug/DefaultGlesDriver.cpp",
+        "debug/GlesErrorCheckWrapper.cpp",
+        "debug/GlesDriver.cpp",
+        "debug/FatalBaseDriver.cpp",
+        "debug/NullGlesDriver.cpp",
+    ],
+    include_dirs: ["frameworks/native/opengl/libs/GLES2"],
+}
+
+cc_defaults {
+    name: "hwui_enable_opengl_validation",
+    defaults: ["hwui_debug"],
+    cflags: ["-DDEBUG_OPENGL=3"],
+    srcs: ["debug/wrap_gles.cpp"],
+    include_dirs: ["frameworks/native/opengl/libs/GLES2"],
+}
+
+// ------------------------
+// library
+// ------------------------
+
+cc_defaults {
+    name: "libhwui_defaults",
+    defaults: ["hwui_defaults"],
+    srcs: [
+        "hwui/Bitmap.cpp",
+        "font/CacheTexture.cpp",
+        "font/Font.cpp",
+        "hwui/Canvas.cpp",
+        "hwui/MinikinSkia.cpp",
+        "hwui/MinikinUtils.cpp",
+        "hwui/PaintImpl.cpp",
+        "hwui/Typeface.cpp",
+        "pipeline/skia/GLFunctorDrawable.cpp",
+        "pipeline/skia/LayerDrawable.cpp",
+        "pipeline/skia/RenderNodeDrawable.cpp",
+        "pipeline/skia/ReorderBarrierDrawables.cpp",
+        "pipeline/skia/SkiaDisplayList.cpp",
+        "pipeline/skia/SkiaOpenGLPipeline.cpp",
+        "pipeline/skia/SkiaOpenGLReadback.cpp",
+        "pipeline/skia/SkiaPipeline.cpp",
+        "pipeline/skia/SkiaProfileRenderer.cpp",
+        "pipeline/skia/SkiaRecordingCanvas.cpp",
+        "pipeline/skia/SkiaVulkanPipeline.cpp",
+        "renderstate/Blend.cpp",
+        "renderstate/MeshState.cpp",
+        "renderstate/OffscreenBufferPool.cpp",
+        "renderstate/PixelBufferState.cpp",
+        "renderstate/RenderState.cpp",
+        "renderstate/Scissor.cpp",
+        "renderstate/Stencil.cpp",
+        "renderstate/TextureState.cpp",
+        "renderthread/CanvasContext.cpp",
+        "renderthread/OpenGLPipeline.cpp",
+        "renderthread/DrawFrameTask.cpp",
+        "renderthread/EglManager.cpp",
+        "renderthread/VulkanManager.cpp",
+        "renderthread/RenderProxy.cpp",
+        "renderthread/RenderTask.cpp",
+        "renderthread/RenderThread.cpp",
+        "renderthread/TimeLord.cpp",
+        "renderthread/Frame.cpp",
+        "service/GraphicsStatsService.cpp",
+        "thread/TaskManager.cpp",
+        "utils/Blur.cpp",
+        "utils/Color.cpp",
+        "utils/GLUtils.cpp",
+        "utils/LinearAllocator.cpp",
+        "utils/StringUtils.cpp",
+        "utils/TestWindowContext.cpp",
+        "utils/VectorDrawableUtils.cpp",
+        "AmbientShadow.cpp",
+        "AnimationContext.cpp",
+        "Animator.cpp",
+        "AnimatorManager.cpp",
+        "BakedOpDispatcher.cpp",
+        "BakedOpRenderer.cpp",
+        "BakedOpState.cpp",
+        "Caches.cpp",
+        "CanvasState.cpp",
+        "ClipArea.cpp",
+        "DamageAccumulator.cpp",
+        "DeferredLayerUpdater.cpp",
+        "DeviceInfo.cpp",
+        "DisplayList.cpp",
+        "Extensions.cpp",
+        "FboCache.cpp",
+        "FontRenderer.cpp",
+        "FrameBuilder.cpp",
+        "FrameInfo.cpp",
+        "FrameInfoVisualizer.cpp",
+        "GammaFontRenderer.cpp",
+        "GlLayer.cpp",
+        "GlopBuilder.cpp",
+        "GpuMemoryTracker.cpp",
+        "GradientCache.cpp",
+        "Image.cpp",
+        "Interpolator.cpp",
+        "JankTracker.cpp",
+        "Layer.cpp",
+        "LayerBuilder.cpp",
+        "LayerUpdateQueue.cpp",
+        "Matrix.cpp",
+        "OpDumper.cpp",
+        "OpenGLReadback.cpp",
+        "Patch.cpp",
+        "PatchCache.cpp",
+        "PathCache.cpp",
+        "PathParser.cpp",
+        "PathTessellator.cpp",
+        "PixelBuffer.cpp",
+        "ProfileRenderer.cpp",
+        "Program.cpp",
+        "ProgramCache.cpp",
+        "Properties.cpp",
+        "PropertyValuesAnimatorSet.cpp",
+        "PropertyValuesHolder.cpp",
+        "RecordingCanvas.cpp",
+        "RenderBufferCache.cpp",
+        "RenderNode.cpp",
+        "RenderProperties.cpp",
+        "ResourceCache.cpp",
+        "ShadowTessellator.cpp",
+        "SkiaCanvas.cpp",
+        "SkiaCanvasProxy.cpp",
+        "SkiaShader.cpp",
+        "Snapshot.cpp",
+        "SpotShadow.cpp",
+        "TessellationCache.cpp",
+        "TextDropShadowCache.cpp",
+        "Texture.cpp",
+        "TextureCache.cpp",
+        "VectorDrawable.cpp",
+        "VkLayer.cpp",
+        "protos/hwui.proto",
+    ],
+
+    proto: {
+        export_proto_headers: true,
+    },
+
+    export_include_dirs: ["."],
+    export_shared_lib_headers: ["libRScpp"],
+}
+
+cc_library {
+    name: "libhwui",
+    defaults: ["libhwui_defaults"],
+}
+
+// ------------------------
+// static library null gpu
+// ------------------------
+
+cc_library_static {
+    name: "libhwui_static_debug",
+    defaults: [
+        "libhwui_defaults",
+        "hwui_debug",
+    ],
+    cflags: ["-DHWUI_NULL_GPU"],
+    srcs: [
+        "debug/nullegl.cpp",
+    ],
+}
+
+cc_defaults {
+    name: "hwui_test_defaults",
+    defaults: ["hwui_defaults"],
+    test_suites: ["device-tests"],
+    srcs: [
+        "tests/common/scenes/*.cpp",
+        "tests/common/LeakChecker.cpp",
+        "tests/common/TestListViewSceneBase.cpp",
+        "tests/common/TestContext.cpp",
+        "tests/common/TestScene.cpp",
+        "tests/common/TestUtils.cpp",
+    ],
+}
+
+// ------------------------
+// unit tests
+// ------------------------
+
+cc_test {
+    name: "hwui_unit_tests",
+    defaults: ["hwui_test_defaults"],
+
+    static_libs: [
+        "libgmock",
+        "libhwui_static_debug",
+    ],
+    shared_libs: ["libmemunreachable"],
+    cflags: [
+        "-include debug/wrap_gles.h",
+        "-DHWUI_NULL_GPU",
+    ],
+
+    srcs: [
+        "tests/unit/main.cpp",
+        "tests/unit/BakedOpDispatcherTests.cpp",
+        "tests/unit/BakedOpRendererTests.cpp",
+        "tests/unit/BakedOpStateTests.cpp",
+        "tests/unit/BitmapTests.cpp",
+        "tests/unit/CanvasContextTests.cpp",
+        "tests/unit/CanvasStateTests.cpp",
+        "tests/unit/ClipAreaTests.cpp",
+        "tests/unit/DamageAccumulatorTests.cpp",
+        "tests/unit/DeferredLayerUpdaterTests.cpp",
+        "tests/unit/DeviceInfoTests.cpp",
+        "tests/unit/FatVectorTests.cpp",
+        "tests/unit/FontRendererTests.cpp",
+        "tests/unit/FrameBuilderTests.cpp",
+        "tests/unit/GlopBuilderTests.cpp",
+        "tests/unit/GpuMemoryTrackerTests.cpp",
+        "tests/unit/GradientCacheTests.cpp",
+        "tests/unit/GraphicsStatsServiceTests.cpp",
+        "tests/unit/LayerUpdateQueueTests.cpp",
+        "tests/unit/LeakCheckTests.cpp",
+        "tests/unit/LinearAllocatorTests.cpp",
+        "tests/unit/MatrixTests.cpp",
+        "tests/unit/MeshStateTests.cpp",
+        "tests/unit/OffscreenBufferPoolTests.cpp",
+        "tests/unit/OpDumperTests.cpp",
+        "tests/unit/PathInterpolatorTests.cpp",
+        "tests/unit/RenderNodeDrawableTests.cpp",
+        "tests/unit/RecordingCanvasTests.cpp",
+        "tests/unit/RenderNodeTests.cpp",
+        "tests/unit/RenderPropertiesTests.cpp",
+        "tests/unit/SkiaBehaviorTests.cpp",
+        "tests/unit/SkiaDisplayListTests.cpp",
+        "tests/unit/SkiaPipelineTests.cpp",
+        "tests/unit/SkiaRenderPropertiesTests.cpp",
+        "tests/unit/SkiaCanvasTests.cpp",
+        "tests/unit/SnapshotTests.cpp",
+        "tests/unit/StringUtilsTests.cpp",
+        "tests/unit/TestUtilsTests.cpp",
+        "tests/unit/TextDropShadowCacheTests.cpp",
+        "tests/unit/TextureCacheTests.cpp",
+	"tests/unit/TypefaceTests.cpp",
+        "tests/unit/VectorDrawableTests.cpp",
+    ],
+}
+
+// ------------------------
+// Macro-bench app
+// ------------------------
+
+cc_benchmark {
+    name: "hwuimacro",
+    defaults: ["hwui_test_defaults"],
+
+    // set to libhwui_static_debug to skip actual GL commands
+    whole_static_libs: ["libhwui"],
+    shared_libs: ["libmemunreachable"],
+
+    srcs: [
+        "tests/macrobench/TestSceneRunner.cpp",
+        "tests/macrobench/main.cpp",
+    ],
+}
+
+// ------------------------
+// Micro-bench app
+// ---------------------
+
+cc_benchmark {
+    name: "hwuimicro",
+    defaults: ["hwui_test_defaults"],
+
+    cflags: [
+        "-include debug/wrap_gles.h",
+        "-DHWUI_NULL_GPU",
+    ],
+
+    whole_static_libs: ["libhwui_static_debug"],
+    shared_libs: ["libmemunreachable"],
+
+    srcs: [
+        "tests/microbench/main.cpp",
+        "tests/microbench/DisplayListCanvasBench.cpp",
+        "tests/microbench/FontBench.cpp",
+        "tests/microbench/FrameBuilderBench.cpp",
+        "tests/microbench/LinearAllocatorBench.cpp",
+        "tests/microbench/PathParserBench.cpp",
+        "tests/microbench/RenderNodeBench.cpp",
+        "tests/microbench/ShadowBench.cpp",
+        "tests/microbench/TaskManagerBench.cpp",
+    ],
+}
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
deleted file mode 100644
index 1e0eeb1..0000000
--- a/libs/hwui/Android.mk
+++ /dev/null
@@ -1,386 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-
-BUGREPORT_FONT_CACHE_USAGE := false
-
-# Enables fine-grained GLES error checking
-# If set to true, every GLES call is wrapped & error checked
-# Has moderate overhead
-HWUI_ENABLE_OPENGL_VALIDATION := false
-
-hwui_src_files := \
-    hwui/Bitmap.cpp \
-    font/CacheTexture.cpp \
-    font/Font.cpp \
-    hwui/Canvas.cpp \
-    hwui/MinikinSkia.cpp \
-    hwui/MinikinUtils.cpp \
-    hwui/PaintImpl.cpp \
-    hwui/Typeface.cpp \
-    pipeline/skia/GLFunctorDrawable.cpp \
-    pipeline/skia/LayerDrawable.cpp \
-    pipeline/skia/RenderNodeDrawable.cpp \
-    pipeline/skia/ReorderBarrierDrawables.cpp \
-    pipeline/skia/SkiaDisplayList.cpp \
-    pipeline/skia/SkiaOpenGLPipeline.cpp \
-    pipeline/skia/SkiaOpenGLReadback.cpp \
-    pipeline/skia/SkiaPipeline.cpp \
-    pipeline/skia/SkiaProfileRenderer.cpp \
-    pipeline/skia/SkiaRecordingCanvas.cpp \
-    pipeline/skia/SkiaVulkanPipeline.cpp \
-    renderstate/Blend.cpp \
-    renderstate/MeshState.cpp \
-    renderstate/OffscreenBufferPool.cpp \
-    renderstate/PixelBufferState.cpp \
-    renderstate/RenderState.cpp \
-    renderstate/Scissor.cpp \
-    renderstate/Stencil.cpp \
-    renderstate/TextureState.cpp \
-    renderthread/CanvasContext.cpp \
-    renderthread/OpenGLPipeline.cpp \
-    renderthread/DrawFrameTask.cpp \
-    renderthread/EglManager.cpp \
-    renderthread/VulkanManager.cpp \
-    renderthread/RenderProxy.cpp \
-    renderthread/RenderTask.cpp \
-    renderthread/RenderThread.cpp \
-    renderthread/TimeLord.cpp \
-    renderthread/Frame.cpp \
-    service/GraphicsStatsService.cpp \
-    thread/TaskManager.cpp \
-    utils/Blur.cpp \
-    utils/Color.cpp \
-    utils/GLUtils.cpp \
-    utils/LinearAllocator.cpp \
-    utils/StringUtils.cpp \
-    utils/TestWindowContext.cpp \
-    utils/VectorDrawableUtils.cpp \
-    AmbientShadow.cpp \
-    AnimationContext.cpp \
-    Animator.cpp \
-    AnimatorManager.cpp \
-    BakedOpDispatcher.cpp \
-    BakedOpRenderer.cpp \
-    BakedOpState.cpp \
-    Caches.cpp \
-    CanvasState.cpp \
-    ClipArea.cpp \
-    DamageAccumulator.cpp \
-    DeferredLayerUpdater.cpp \
-    DeviceInfo.cpp \
-    DisplayList.cpp \
-    Extensions.cpp \
-    FboCache.cpp \
-    FontRenderer.cpp \
-    FrameBuilder.cpp \
-    FrameInfo.cpp \
-    FrameInfoVisualizer.cpp \
-    GammaFontRenderer.cpp \
-    GlLayer.cpp \
-    GlopBuilder.cpp \
-    GpuMemoryTracker.cpp \
-    GradientCache.cpp \
-    Image.cpp \
-    Interpolator.cpp \
-    JankTracker.cpp \
-    Layer.cpp \
-    LayerBuilder.cpp \
-    LayerUpdateQueue.cpp \
-    Matrix.cpp \
-    OpDumper.cpp \
-    OpenGLReadback.cpp \
-    Patch.cpp \
-    PatchCache.cpp \
-    PathCache.cpp \
-    PathParser.cpp \
-    PathTessellator.cpp \
-    PixelBuffer.cpp \
-    ProfileRenderer.cpp \
-    Program.cpp \
-    ProgramCache.cpp \
-    Properties.cpp \
-    PropertyValuesAnimatorSet.cpp \
-    PropertyValuesHolder.cpp \
-    RecordingCanvas.cpp \
-    RenderBufferCache.cpp \
-    RenderNode.cpp \
-    RenderProperties.cpp \
-    ResourceCache.cpp \
-    ShadowTessellator.cpp \
-    SkiaCanvas.cpp \
-    SkiaCanvasProxy.cpp \
-    SkiaShader.cpp \
-    Snapshot.cpp \
-    SpotShadow.cpp \
-    TessellationCache.cpp \
-    TextDropShadowCache.cpp \
-    Texture.cpp \
-    TextureCache.cpp \
-    VectorDrawable.cpp \
-    VkLayer.cpp \
-    protos/hwui.proto
-
-hwui_test_common_src_files := \
-    $(call all-cpp-files-under, tests/common/scenes) \
-    tests/common/LeakChecker.cpp \
-    tests/common/TestListViewSceneBase.cpp \
-    tests/common/TestContext.cpp \
-    tests/common/TestScene.cpp \
-    tests/common/TestUtils.cpp
-
-hwui_debug_common_src_files := \
-    debug/wrap_gles.cpp \
-    debug/DefaultGlesDriver.cpp \
-    debug/GlesErrorCheckWrapper.cpp \
-    debug/GlesDriver.cpp \
-    debug/FatalBaseDriver.cpp \
-    debug/NullGlesDriver.cpp
-
-hwui_cflags := \
-    -DEGL_EGLEXT_PROTOTYPES -DGL_GLEXT_PROTOTYPES \
-    -DATRACE_TAG=ATRACE_TAG_VIEW -DLOG_TAG=\"OpenGLRenderer\" \
-    -Wall -Wno-unused-parameter -Wunreachable-code -Werror
-
-ifeq ($(TARGET_USES_HWC2),true)
-    hwui_cflags += -DUSE_HWC2
-endif
-
-# TODO: Linear blending should be enabled by default, but we are
-# TODO: making it an opt-in while it's a work in progress
-# TODO: The final test should be:
-# TODO: ifneq ($(TARGET_ENABLE_LINEAR_BLENDING),false)
-ifeq ($(TARGET_ENABLE_LINEAR_BLENDING),true)
-    hwui_cflags += -DANDROID_ENABLE_LINEAR_BLENDING
-endif
-
-# GCC false-positives on this warning, and since we -Werror that's
-# a problem
-hwui_cflags += -Wno-free-nonheap-object
-
-# clang's warning is broken, see: https://llvm.org/bugs/show_bug.cgi?id=21629
-hwui_cflags += -Wno-missing-braces
-
-ifeq (true, $(BUGREPORT_FONT_CACHE_USAGE))
-    hwui_src_files += \
-        font/FontCacheHistoryTracker.cpp
-    hwui_cflags += -DBUGREPORT_FONT_CACHE_USAGE
-endif
-
-ifndef HWUI_COMPILE_SYMBOLS
-    hwui_cflags += -fvisibility=hidden
-endif
-
-ifdef HWUI_COMPILE_FOR_PERF
-    # TODO: Non-arm?
-    hwui_cflags += -fno-omit-frame-pointer -marm -mapcs
-endif
-
-# This has to be lazy-resolved because it depends on the LOCAL_MODULE_CLASS
-# which varies depending on what is being built
-define hwui_proto_include
-$(call local-generated-sources-dir)/proto/$(LOCAL_PATH)
-endef
-
-hwui_c_includes += \
-    external/skia/include/private \
-    external/skia/src/core \
-    external/skia/src/effects \
-    external/skia/src/image \
-    external/skia/src/utils \
-    external/icu/icu4c/source/common \
-    external/harfbuzz_ng/src \
-    external/freetype/include
-
-# enable RENDERSCRIPT
-hwui_c_includes += \
-    $(call intermediates-dir-for,STATIC_LIBRARIES,TARGET,) \
-    frameworks/rs/cpp \
-    frameworks/rs
-
-# ------------------------
-# static library
-# ------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := libhwui_static
-LOCAL_CFLAGS := $(hwui_cflags)
-LOCAL_SRC_FILES := $(hwui_src_files)
-
-ifeq (true, $(HWUI_ENABLE_OPENGL_VALIDATION))
-    LOCAL_CFLAGS += -include debug/wrap_gles.h
-    LOCAL_CFLAGS += -DDEBUG_OPENGL=3
-    LOCAL_SRC_FILES += $(hwui_debug_common_src_files)
-endif
-
-LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
-        $(LOCAL_PATH) \
-        $(call hwui_proto_include)
-
-include $(LOCAL_PATH)/hwui_static_deps.mk
-include $(BUILD_STATIC_LIBRARY)
-
-# ------------------------
-# static library null gpu
-# ------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE := libhwui_static_debug
-LOCAL_CFLAGS := \
-        $(hwui_cflags) \
-        -include debug/wrap_gles.h \
-        -DHWUI_NULL_GPU
-LOCAL_SRC_FILES := \
-        $(hwui_src_files) \
-        $(hwui_debug_common_src_files) \
-        debug/nullegl.cpp
-LOCAL_C_INCLUDES := $(hwui_c_includes) $(call hwui_proto_include)
-LOCAL_EXPORT_C_INCLUDE_DIRS := \
-        $(LOCAL_PATH) \
-        $(call hwui_proto_include)
-
-include $(LOCAL_PATH)/hwui_static_deps.mk
-include $(BUILD_STATIC_LIBRARY)
-
-# ------------------------
-# shared library
-# ------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_MODULE := libhwui
-LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static
-LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-
-include $(LOCAL_PATH)/hwui_static_deps.mk
-include $(BUILD_SHARED_LIBRARY)
-
-# ------------------------
-# unit tests
-# ------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := hwui_unit_tests
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_LIBRARIES := libgmock libhwui_static_debug
-LOCAL_SHARED_LIBRARIES := libmemunreachable
-LOCAL_CFLAGS := \
-        $(hwui_cflags) \
-        -include debug/wrap_gles.h \
-        -DHWUI_NULL_GPU
-LOCAL_C_INCLUDES := $(hwui_c_includes)
-
-LOCAL_SRC_FILES += \
-    $(hwui_test_common_src_files) \
-    tests/unit/main.cpp \
-    tests/unit/BakedOpDispatcherTests.cpp \
-    tests/unit/BakedOpRendererTests.cpp \
-    tests/unit/BakedOpStateTests.cpp \
-    tests/unit/BitmapTests.cpp \
-    tests/unit/CanvasContextTests.cpp \
-    tests/unit/CanvasStateTests.cpp \
-    tests/unit/ClipAreaTests.cpp \
-    tests/unit/DamageAccumulatorTests.cpp \
-    tests/unit/DeferredLayerUpdaterTests.cpp \
-    tests/unit/DeviceInfoTests.cpp \
-    tests/unit/FatVectorTests.cpp \
-    tests/unit/FontRendererTests.cpp \
-    tests/unit/FrameBuilderTests.cpp \
-    tests/unit/GlopBuilderTests.cpp \
-    tests/unit/GpuMemoryTrackerTests.cpp \
-    tests/unit/GradientCacheTests.cpp \
-    tests/unit/GraphicsStatsServiceTests.cpp \
-    tests/unit/LayerUpdateQueueTests.cpp \
-    tests/unit/LeakCheckTests.cpp \
-    tests/unit/LinearAllocatorTests.cpp \
-    tests/unit/MatrixTests.cpp \
-    tests/unit/MeshStateTests.cpp \
-    tests/unit/OffscreenBufferPoolTests.cpp \
-    tests/unit/OpDumperTests.cpp \
-    tests/unit/PathInterpolatorTests.cpp \
-    tests/unit/RenderNodeDrawableTests.cpp \
-    tests/unit/RecordingCanvasTests.cpp \
-    tests/unit/RenderNodeTests.cpp \
-    tests/unit/RenderPropertiesTests.cpp \
-    tests/unit/SkiaBehaviorTests.cpp \
-    tests/unit/SkiaDisplayListTests.cpp \
-    tests/unit/SkiaPipelineTests.cpp \
-    tests/unit/SkiaRenderPropertiesTests.cpp \
-    tests/unit/SkiaCanvasTests.cpp \
-    tests/unit/SnapshotTests.cpp \
-    tests/unit/StringUtilsTests.cpp \
-    tests/unit/TestUtilsTests.cpp \
-    tests/unit/TextDropShadowCacheTests.cpp \
-    tests/unit/TextureCacheTests.cpp \
-    tests/unit/VectorDrawableTests.cpp \
-
-include $(LOCAL_PATH)/hwui_static_deps.mk
-include $(BUILD_NATIVE_TEST)
-
-# ------------------------
-# Macro-bench app
-# ------------------------
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/local/tmp
-LOCAL_MODULE:= hwuimacro
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-LOCAL_MULTILIB := both
-LOCAL_CFLAGS := $(hwui_cflags)
-LOCAL_C_INCLUDES := $(hwui_c_includes)
-
-# set to libhwui_static_debug to skip actual GL commands
-LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static
-LOCAL_SHARED_LIBRARIES := libmemunreachable
-
-LOCAL_SRC_FILES += \
-    $(hwui_test_common_src_files) \
-    tests/macrobench/TestSceneRunner.cpp \
-    tests/macrobench/main.cpp
-
-include $(LOCAL_PATH)/hwui_static_deps.mk
-include $(BUILD_NATIVE_BENCHMARK)
-
-# ------------------------
-# Micro-bench app
-# ---------------------
-include $(CLEAR_VARS)
-
-LOCAL_MODULE:= hwuimicro
-LOCAL_COMPATIBILITY_SUITE := device-tests
-LOCAL_MODULE_TAGS := tests
-LOCAL_CFLAGS := \
-        $(hwui_cflags) \
-        -include debug/wrap_gles.h \
-        -DHWUI_NULL_GPU
-
-LOCAL_C_INCLUDES := $(hwui_c_includes)
-
-LOCAL_WHOLE_STATIC_LIBRARIES := libhwui_static_debug
-LOCAL_SHARED_LIBRARIES := libmemunreachable
-
-LOCAL_SRC_FILES += \
-    $(hwui_test_common_src_files) \
-    tests/microbench/main.cpp \
-    tests/microbench/DisplayListCanvasBench.cpp \
-    tests/microbench/FontBench.cpp \
-    tests/microbench/FrameBuilderBench.cpp \
-    tests/microbench/LinearAllocatorBench.cpp \
-    tests/microbench/PathParserBench.cpp \
-    tests/microbench/RenderNodeBench.cpp \
-    tests/microbench/ShadowBench.cpp \
-    tests/microbench/TaskManagerBench.cpp
-
-
-include $(LOCAL_PATH)/hwui_static_deps.mk
-include $(BUILD_NATIVE_BENCHMARK)
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index 34c7934..e91c08d 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -110,6 +110,7 @@
         } vertices;
 
         int elementCount;
+        int vertexCount; // only used for meshes (for glDrawRangeElements)
         TextureVertex mappedVertices[4];
     } mesh;
 
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 931a55a..2e9a6e8 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -199,6 +199,7 @@
             alphaVertex ? kAlphaVertexStride : kVertexStride };
     mOutGlop->mesh.elementCount = indices
                 ? vertexBuffer.getIndexCount() : vertexBuffer.getVertexCount();
+    mOutGlop->mesh.vertexCount = vertexBuffer.getVertexCount(); // used for glDrawRangeElements()
     return *this;
 }
 
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index 929d1606..d8207b1 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -317,7 +317,17 @@
 }
 
 void Bitmap::setColorSpace(sk_sp<SkColorSpace> colorSpace) {
-    reconfigure(info().makeColorSpace(std::move(colorSpace)), rowBytes(), sk_ref_sp(colorTable()));
+    mInfo = mInfo.makeColorSpace(std::move(colorSpace));
+}
+
+static SkImageInfo validateAlpha(const SkImageInfo& info) {
+    // Need to validate the alpha type to filter against the color type
+    // to prevent things like a non-opaque RGB565 bitmap
+    SkAlphaType alphaType;
+    LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
+            info.colorType(), info.alphaType(), &alphaType),
+            "Failed to validate alpha type!");
+    return info.makeAlphaType(alphaType);
 }
 
 void Bitmap::reconfigure(const SkImageInfo& newInfo, size_t rowBytes, sk_sp<SkColorTable> ctable) {
@@ -325,19 +335,14 @@
         ctable = nullptr;
     }
 
-    // Need to validate the alpha type to filter against the color type
-    // to prevent things like a non-opaque RGB565 bitmap
-    SkAlphaType alphaType;
-    LOG_ALWAYS_FATAL_IF(!SkColorTypeValidateAlphaType(
-            newInfo.colorType(), newInfo.alphaType(), &alphaType),
-            "Failed to validate alpha type!");
+    mInfo = validateAlpha(newInfo);
 
     // Dirty hack is dirty
     // TODO: Figure something out here, Skia's current design makes this
     // really hard to work with. Skia really, really wants immutable objects,
     // but with the nested-ref-count hackery going on that's just not
     // feasible without going insane trying to figure it out
-    this->android_only_reset(newInfo.makeAlphaType(alphaType), rowBytes, std::move(ctable));
+    this->android_only_reset(mInfo.width(), mInfo.height(), rowBytes, std::move(ctable));
 }
 
 static sk_sp<SkColorTable> sanitize(const SkImageInfo& info, sk_sp<SkColorTable> ctable) {
@@ -347,8 +352,11 @@
     }
     return nullptr; // drop the ctable if we're not indexed
 }
-Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes, sk_sp<SkColorTable> ctable)
-            : SkPixelRef(info, address, rowBytes, sanitize(info, std::move(ctable)))
+Bitmap::Bitmap(void* address, size_t size, const SkImageInfo& info, size_t rowBytes,
+        sk_sp<SkColorTable> ctable)
+            : SkPixelRef(info.width(), info.height(), address, rowBytes,
+                    sanitize(info, std::move(ctable)))
+            , mInfo(validateAlpha(info))
             , mPixelStorageType(PixelStorageType::Heap) {
     mPixelStorage.heap.address = address;
     mPixelStorage.heap.size = size;
@@ -356,7 +364,9 @@
 
 Bitmap::Bitmap(void* address, void* context, FreeFunc freeFunc,
                 const SkImageInfo& info, size_t rowBytes, sk_sp<SkColorTable> ctable)
-            : SkPixelRef(info, address, rowBytes, sanitize(info, std::move(ctable)))
+            : SkPixelRef(info.width(), info.height(), address, rowBytes,
+                    sanitize(info, std::move(ctable)))
+            , mInfo(validateAlpha(info))
             , mPixelStorageType(PixelStorageType::External) {
     mPixelStorage.external.address = address;
     mPixelStorage.external.context = context;
@@ -365,7 +375,9 @@
 
 Bitmap::Bitmap(void* address, int fd, size_t mappedSize,
                 const SkImageInfo& info, size_t rowBytes, sk_sp<SkColorTable> ctable)
-            : SkPixelRef(info, address, rowBytes, sanitize(info, std::move(ctable)))
+            : SkPixelRef(info.width(), info.height(), address, rowBytes,
+                    sanitize(info, std::move(ctable)))
+            , mInfo(validateAlpha(info))
             , mPixelStorageType(PixelStorageType::Ashmem) {
     mPixelStorage.ashmem.address = address;
     mPixelStorage.ashmem.fd = fd;
@@ -373,9 +385,10 @@
 }
 
 Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
-        : SkPixelRef(info, nullptr,
+        : SkPixelRef(info.width(), info.height(), nullptr,
                      bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride(),
                      nullptr)
+        , mInfo(validateAlpha(info))
         , mPixelStorageType(PixelStorageType::Hardware) {
     mPixelStorage.hardware.buffer = buffer;
     buffer->incStrong(buffer);
@@ -428,10 +441,6 @@
     }
 }
 
-size_t Bitmap::getAllocatedSizeInBytes() const {
-    return info().getSafeSize(this->rowBytes());
-}
-
 int Bitmap::getAshmemFd() const {
     switch (mPixelStorageType) {
     case PixelStorageType::Ashmem:
@@ -459,30 +468,29 @@
         return;
     }
 
-    changeAlphaType(alphaType);
+    mInfo = mInfo.makeAlphaType(alphaType);
 }
 
 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
     outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
     if (isHardware()) {
-        ALOGW("Warning: attempt to read pixels from hardware bitmap, which is very slow operation");
         outBitmap->allocPixels(info());
         uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
         return;
     }
-    outBitmap->setInfo(info(), rowBytes());
+    outBitmap->setInfo(mInfo, rowBytes());
     outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
 }
 
 void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) {
-    outBitmap->setInfo(info(), rowBytes());
+    outBitmap->setInfo(mInfo, rowBytes());
     outBitmap->setPixelRef(sk_ref_sp(this), 0, 0);
     outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
 }
 
 void Bitmap::getBounds(SkRect* bounds) const {
     SkASSERT(bounds);
-    bounds->set(0, 0, SkIntToScalar(info().width()), SkIntToScalar(info().height()));
+    bounds->set(0, 0, SkIntToScalar(width()), SkIntToScalar(height()));
 }
 
 GraphicBuffer* Bitmap::graphicBuffer() {
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index 701b9db..9a76715 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -67,11 +67,8 @@
     Bitmap(void* address, int fd, size_t mappedSize, const SkImageInfo& info,
             size_t rowBytes, sk_sp<SkColorTable> ctable);
 
-    int width() const { return info().width(); }
-    int height() const { return info().height(); }
-
     int rowBytesAsPixels() const {
-        return rowBytes() >> info().shiftPerPixel();
+        return rowBytes() >> SkColorTypeShiftPerPixel(mInfo.colorType());
     }
 
     void reconfigure(const SkImageInfo& info, size_t rowBytes, sk_sp<SkColorTable> ctable);
@@ -91,8 +88,12 @@
     void setHasHardwareMipMap(bool hasMipMap);
     bool hasHardwareMipMap() const;
 
-    bool isOpaque() const {return info().isOpaque(); }
-    SkColorType colorType() const { return info().colorType(); }
+    bool isOpaque() const { return mInfo.isOpaque(); }
+    SkColorType colorType() const { return mInfo.colorType(); }
+    const SkImageInfo& info() const {
+        return mInfo;
+    }
+
     void getBounds(SkRect* bounds) const;
 
     bool readyToDraw() const {
@@ -104,13 +105,13 @@
     }
 
     GraphicBuffer* graphicBuffer();
-protected:
-    virtual size_t getAllocatedSizeInBytes() const override;
 private:
     Bitmap(GraphicBuffer* buffer, const SkImageInfo& info);
     virtual ~Bitmap();
     void* getStorage() const;
 
+    SkImageInfo mInfo;
+
     const PixelStorageType mPixelStorageType;
 
     bool mHasHardwareMipMap = false;
@@ -136,4 +137,4 @@
     } mPixelStorage;
 };
 
-} //namespace android
\ No newline at end of file
+} //namespace android
diff --git a/libs/hwui/hwui/Typeface.cpp b/libs/hwui/hwui/Typeface.cpp
index 4fb4b53..f66bb04 100644
--- a/libs/hwui/hwui/Typeface.cpp
+++ b/libs/hwui/hwui/Typeface.cpp
@@ -36,28 +36,33 @@
 #include <minikin/FontFamily.h>
 #include <minikin/Layout.h>
 #include <utils/Log.h>
+#include <utils/MathUtils.h>
 
 namespace android {
 
-// This indicates that the passed information should be resolved by OS/2 table.
-// This value must be the same as the android.graphics.Typeface$Builder.RESOLVE_BY_FONT_TABLE.
-constexpr int RESOLVE_BY_FONT_TABLE = -1;
+static SkTypeface::Style computeSkiaStyle(int weight, bool italic) {
+    // This bold detection comes from SkTypeface.h
+    if (weight >= SkFontStyle::kSemiBold_Weight) {
+        return italic ? SkTypeface::kBoldItalic : SkTypeface::kBold;
+    } else {
+        return italic ? SkTypeface::kItalic : SkTypeface::kNormal;
+    }
+}
 
-// Resolve the 1..10 weight based on base weight and bold flag
-static void resolveStyle(Typeface* typeface) {
+static minikin::FontStyle computeMinikinStyle(int weight, bool italic) {
     // TODO: Better to use raw base weight value for font selection instead of dividing by 100.
-    int weight = (typeface->fBaseWeight + 50) / 100;
-    if (typeface->fSkiaStyle & SkTypeface::kBold) {
-        weight += 3;
+    const int minikinWeight = uirenderer::MathUtils::clamp((weight + 50) / 100, 1, 10);
+    return minikin::FontStyle(minikinWeight, italic);
+}
+
+// Resolve the relative weight from the baseWeight and target style.
+static minikin::FontStyle computeRelativeStyle(int baseWeight, SkTypeface::Style relativeStyle) {
+    int weight = baseWeight;
+    if ((relativeStyle & SkTypeface::kBold) != 0) {
+        weight += 300;
     }
-    if (weight > 10) {
-        weight = 10;
-    }
-    if (weight < 1) {
-        weight = 1;
-    }
-    bool italic = (typeface->fSkiaStyle & SkTypeface::kItalic) != 0;
-    typeface->fStyle = minikin::FontStyle(weight, italic);
+    bool italic = (relativeStyle & SkTypeface::kItalic) != 0;
+    return computeMinikinStyle(weight, italic);
 }
 
 Typeface* gDefaultTypeface = NULL;
@@ -67,26 +72,26 @@
     return src == nullptr ? gDefaultTypeface : src;
 }
 
-Typeface* Typeface::createFromTypeface(Typeface* src, SkTypeface::Style style) {
+Typeface* Typeface::createRelative(Typeface* src, SkTypeface::Style style) {
     Typeface* resolvedFace = Typeface::resolveDefault(src);
     Typeface* result = new Typeface;
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fSkiaStyle = style;
         result->fBaseWeight = resolvedFace->fBaseWeight;
-        resolveStyle(result);
+        result->fSkiaStyle = style;
+        result->fStyle = computeRelativeStyle(result->fBaseWeight, style);
     }
     return result;
 }
 
-Typeface* Typeface::createFromTypefaceWithStyle(Typeface* base, int weight, bool italic) {
+Typeface* Typeface::createAbsolute(Typeface* base, int weight, bool italic) {
     Typeface* resolvedFace = Typeface::resolveDefault(base);
     Typeface* result = new Typeface();
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fBaseWeight = weight;
-        result->fStyle = minikin::FontStyle(weight / 100, italic);
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        result->fBaseWeight = resolvedFace->fBaseWeight;
+        result->fSkiaStyle = computeSkiaStyle(weight, italic);
+        result->fStyle = computeMinikinStyle(weight, italic);
     }
     return result;
 }
@@ -103,21 +108,23 @@
             // So we will reuse the same collection with incrementing reference count.
             result->fFontCollection = resolvedFace->fFontCollection;
         }
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        // Do not update styles.
+        // TODO: We may want to update base weight if the 'wght' is specified.
         result->fBaseWeight = resolvedFace->fBaseWeight;
-        resolveStyle(result);
+        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        result->fStyle = resolvedFace->fStyle;
     }
     return result;
 }
 
-Typeface* Typeface::createWeightAlias(Typeface* src, int weight) {
+Typeface* Typeface::createWithDifferentBaseWeight(Typeface* src, int weight) {
     Typeface* resolvedFace = Typeface::resolveDefault(src);
     Typeface* result = new Typeface;
     if (result != nullptr) {
         result->fFontCollection = resolvedFace->fFontCollection;
-        result->fSkiaStyle = resolvedFace->fSkiaStyle;
         result->fBaseWeight = weight;
-        resolveStyle(result);
+        result->fSkiaStyle = resolvedFace->fSkiaStyle;
+        result->fStyle = computeRelativeStyle(weight, result->fSkiaStyle);
     }
     return result;
 }
@@ -160,14 +167,8 @@
     }
 
     result->fBaseWeight = weight;
-    // This bold detection comes from SkTypefae.h
-    const bool isBold = weight >= SkFontStyle::kSemiBold_Weight;
-    const bool isItalic = italic == 1;
-    // TODO: remove fSkiaStyle
-    result->fSkiaStyle = isBold ?
-            (isItalic ? SkTypeface::kBoldItalic : SkTypeface::kBold) :
-            (isItalic ? SkTypeface::kItalic : SkTypeface::kNormal);
-    resolveStyle(result);
+    result->fSkiaStyle = computeSkiaStyle(weight, italic);
+    result->fStyle = computeMinikinStyle(weight, italic);
     return result;
 }
 
@@ -197,7 +198,7 @@
     Typeface* hwTypeface = new Typeface();
     hwTypeface->fFontCollection = collection;
     hwTypeface->fSkiaStyle = SkTypeface::kNormal;
-    hwTypeface->fBaseWeight = SkFontStyle::kSemiBold_Weight;
+    hwTypeface->fBaseWeight = SkFontStyle::kNormal_Weight;
     hwTypeface->fStyle = minikin::FontStyle(4 /* weight */, false /* italic */);
 
     Typeface::setDefault(hwTypeface);
diff --git a/libs/hwui/hwui/Typeface.h b/libs/hwui/hwui/Typeface.h
index e35a7b4..db0b2cd 100644
--- a/libs/hwui/hwui/Typeface.h
+++ b/libs/hwui/hwui/Typeface.h
@@ -27,28 +27,53 @@
 
 namespace android {
 
-struct ANDROID_API Typeface {
-    std::shared_ptr<minikin::FontCollection> fFontCollection;
+// This indicates that the weight or italic information should be resolved by OS/2 table.
+// This value must be the same as the android.graphics.Typeface$Builder.RESOLVE_BY_FONT_TABLE.
+constexpr int RESOLVE_BY_FONT_TABLE = -1;
 
-    // style used for constructing and querying Typeface objects
-    SkTypeface::Style fSkiaStyle;
-    // base weight in CSS-style units, 100..900
-    int fBaseWeight;
+struct ANDROID_API Typeface {
+ public:
+    std::shared_ptr<minikin::FontCollection> fFontCollection;
 
     // resolved style actually used for rendering
     minikin::FontStyle fStyle;
 
+    // style used for constructing and querying Typeface objects
+    SkTypeface::Style fSkiaStyle;
+
     static Typeface* resolveDefault(Typeface* src);
 
-    static Typeface* createFromTypeface(Typeface* src, SkTypeface::Style style);
-
-    static Typeface* createFromTypefaceWithStyle(Typeface* base, int weight, bool italic);
+    // The following three functions create new Typeface from an existing Typeface with a different
+    // style. There is a base weight concept which is used for calculating relative style from an
+    // existing Typeface.
+    // The createRelative method creates a new Typeface with a style relative to the base Typeface.
+    // For example, if the base Typeface has a base weight of 400 and the desired style is bold, the
+    // resulting Typeface renders the text with a weight of 700. This function doesn't change the
+    // base weight, so even if you create a new Typeface from the bold Typeface specifying bold on
+    // it again, the text is still rendered with a weight of 700.
+    // You can create another base weight Typeface from an existing Typeface with
+    // createWithDifferentBaseWeight. The Typeface created with this function renders the text with
+    // a specified base weight.
+    // The createAbsolute method creates a new Typeface ignoring the base weight.
+    // Here is an example:
+    //   Typeface* base = resolveDefault(nullptr);  // Usually this has a weight of 400.
+    //   Typeface* bold = createRelative(base, Bold);  // Rendered with a weight of 700.
+    //   Typeface* bold2 = createRelative(bold, Bold); // Rendered with a weight of 700.
+    //
+    //   Typeface* boldBase = createWithDifferentBaseWeight(base, 700);  // With a weight of 700.
+    //   Typeface* boldBold = createRelative(boldBase, Bold);  // Rendered with a weight of 1000.
+    //
+    //   Typeface* lightBase = createWithDifferentBaseWeight(base, 300);  // With a weight of 300.
+    //   Typeface* lightBold = createRelative(lightBase, Bold);  // Rendered with a weight of 600.
+    //
+    //   Typeface* black = createAbsolute(base, 900, false);  // Rendered with a weight of 900.
+    static Typeface* createWithDifferentBaseWeight(Typeface* src, int baseweight);
+    static Typeface* createRelative(Typeface* src, SkTypeface::Style desiredStyle);
+    static Typeface* createAbsolute(Typeface* base, int weight, bool italic);
 
     static Typeface* createFromTypefaceWithVariation(Typeface* src,
             const std::vector<minikin::FontVariation>& variations);
 
-    static Typeface* createWeightAlias(Typeface* src, int baseweight);
-
     static Typeface* createFromFamilies(
             std::vector<std::shared_ptr<minikin::FontFamily>>&& families,
             int weight, int italic);
@@ -57,6 +82,10 @@
 
     // Sets roboto font as the default typeface for testing purpose.
     static void setRobotoTypefaceForTest();
+ private:
+    // base weight in CSS-style units, 1..1000
+    int fBaseWeight;
+
 };
 
 }
diff --git a/libs/hwui/hwui_static_deps.mk b/libs/hwui/hwui_static_deps.mk
deleted file mode 100644
index 8826cfc..0000000
--- a/libs/hwui/hwui_static_deps.mk
+++ /dev/null
@@ -1,33 +0,0 @@
-###############################################################################
-#
-#
-# This file contains the shared and static dependencies needed by any target
-# that attempts to statically link HWUI (i.e. libhwui_static build target). This
-# file should be included by any target that lists libhwui_static as a
-# dependency.
-#
-# This is a workaround for the fact that the build system does not add these
-# transitive dependencies when it attempts to link libhwui_static into another
-# library.
-#
-###############################################################################
-
-LOCAL_SHARED_LIBRARIES += \
-    liblog \
-    libcutils \
-    libutils \
-    libEGL \
-    libGLESv2 \
-    libvulkan \
-    libskia \
-    libui \
-    libgui \
-    libprotobuf-cpp-full \
-    libharfbuzz_ng \
-    libft2 \
-    libminikin \
-    libandroidfw \
-    libRScpp
-
-LOCAL_STATIC_LIBRARIES += \
-    libplatformprotos
diff --git a/libs/hwui/renderstate/RenderState.cpp b/libs/hwui/renderstate/RenderState.cpp
index c8833d2..8b737bb 100644
--- a/libs/hwui/renderstate/RenderState.cpp
+++ b/libs/hwui/renderstate/RenderState.cpp
@@ -413,18 +413,28 @@
         const GLbyte* vertexData = static_cast<const GLbyte*>(vertices.position);
         while (elementsCount > 0) {
             GLsizei drawCount = std::min(elementsCount, (GLsizei) kMaxNumberOfQuads * 6);
+            GLsizei vertexCount = (drawCount / 6) * 4;
             meshState().bindPositionVertexPointer(vertexData, vertices.stride);
             if (vertices.attribFlags & VertexAttribFlags::TextureCoord) {
                 meshState().bindTexCoordsVertexPointer(
                         vertexData + kMeshTextureOffset, vertices.stride);
             }
 
-            glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
+            if (mCaches->extensions().getMajorGlVersion() >= 3) {
+                glDrawRangeElements(mesh.primitiveMode, 0, vertexCount-1, drawCount, GL_UNSIGNED_SHORT, nullptr);
+            } else {
+                glDrawElements(mesh.primitiveMode, drawCount, GL_UNSIGNED_SHORT, nullptr);
+            }
             elementsCount -= drawCount;
-            vertexData += (drawCount / 6) * 4 * vertices.stride;
+            vertexData += vertexCount * vertices.stride;
         }
     } else if (indices.bufferObject || indices.indices) {
-        glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+        if (mCaches->extensions().getMajorGlVersion() >= 3) {
+            // use glDrawRangeElements to reduce CPU overhead (otherwise the driver has to determine the min/max index values)
+            glDrawRangeElements(mesh.primitiveMode, 0, mesh.vertexCount-1, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+        } else {
+            glDrawElements(mesh.primitiveMode, mesh.elementCount, GL_UNSIGNED_SHORT, indices.indices);
+        }
     } else {
         glDrawArrays(mesh.primitiveMode, 0, mesh.elementCount);
     }
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index 9a3b81c..c46592c 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -118,7 +118,7 @@
     layerPaint.setAlpha(128);
     OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
     LayerOp op(Rect(10, 10), Matrix4::identity(), nullptr, &layerPaint, &buffer);
-    testUnmergedGlopDispatch(renderThread, &op, [&renderThread] (const Glop& glop) {
+    testUnmergedGlopDispatch(renderThread, &op, [] (const Glop& glop) {
         ADD_FAILURE() << "Nothing should happen";
     }, 0);
 }
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index bd798e8..fcdd814 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -819,7 +819,7 @@
     EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, renderNode) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderNode) {
     class RenderNodeTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -2321,7 +2321,7 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedInMiddle) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedInMiddle) {
     /* R is backward projected on B
                 A
                / \
@@ -2351,7 +2351,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectLast) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectLast) {
     /* R is backward projected on E
                   A
                 / | \
@@ -2383,7 +2383,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderNoReceivable) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderNoReceivable) {
     /* R is backward projected without receiver
                 A
                / \
@@ -2412,7 +2412,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderParentReceivable) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderParentReceivable) {
     /* R is backward projected on C
                 A
                / \
@@ -2441,7 +2441,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderSameNodeReceivable) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderSameNodeReceivable) {
      auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         drawOrderedNode(&canvas, 0, nullptr); //nodeB
@@ -2464,7 +2464,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling) {
     //TODO: this test together with the next "projectionReorderProjectedSibling2" likely expose a
     //bug in HWUI. First test draws R, while the second test does not draw R for a nearly identical
     //tree setup. The correct behaviour is to not draw R, because the receiver cannot be a sibling
@@ -2497,7 +2497,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling2) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedSibling2) {
     /* R is set to project on B, but R is not drawn because projecting on a sibling is not allowed.
                 A
                 |
@@ -2530,7 +2530,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderGrandparentReceivable) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderGrandparentReceivable) {
     /* R is backward projected on B
                 A
                 |
@@ -2562,7 +2562,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivables) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivables) {
     /* B and G are receivables, R is backward projected
                 A
                / \
@@ -2595,7 +2595,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesLikelyScenario) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesLikelyScenario) {
     /* B and G are receivables, G is backward projected
                 A
                / \
@@ -2628,7 +2628,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesDeeper) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesDeeper) {
     /* B and G are receivables, R is backward projected
                 A
                / \
diff --git a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
index cfe1134..f6f7337 100644
--- a/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
+++ b/libs/hwui/tests/unit/GraphicsStatsServiceTests.cpp
@@ -50,7 +50,11 @@
 
 // No code left untested
 TEST(GraphicsStats, findRootPath) {
+#ifdef __LP64__
+    std::string expected = "/data/nativetest64/hwui_unit_tests";
+#else
     std::string expected = "/data/nativetest/hwui_unit_tests";
+#endif
     EXPECT_EQ(expected, findRootPath());
 }
 
@@ -156,4 +160,4 @@
         EXPECT_EQ(expectedCount, loadedProto.histogram().Get(i).frame_count());
         EXPECT_EQ(expectedBucket, loadedProto.histogram().Get(i).render_millis());
     }
-}
\ No newline at end of file
+}
diff --git a/libs/hwui/tests/unit/TypefaceTests.cpp b/libs/hwui/tests/unit/TypefaceTests.cpp
new file mode 100644
index 0000000..c90b6f0
--- /dev/null
+++ b/libs/hwui/tests/unit/TypefaceTests.cpp
@@ -0,0 +1,418 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <utils/Log.h>
+
+#include "SkFontMgr.h"
+#include "SkStream.h"
+
+#include "hwui/MinikinSkia.h"
+#include "hwui/Typeface.h"
+
+using namespace android;
+
+namespace {
+
+constexpr char kRobotoRegular[] = "/system/fonts/Roboto-Regular.ttf";
+constexpr char kRobotoBold[] = "/system/fonts/Roboto-Bold.ttf";
+constexpr char kRobotoItalic[] = "/system/fonts/Roboto-Italic.ttf";
+constexpr char kRobotoBoldItalic[] = "/system/fonts/Roboto-BoldItalic.ttf";
+
+void unmap(const void* ptr, void* context) {
+    void* p = const_cast<void*>(ptr);
+    size_t len = reinterpret_cast<size_t>(context);
+    munmap(p, len);
+}
+
+std::shared_ptr<minikin::FontFamily> buildFamily(const char* fileName) {
+    int fd = open(fileName, O_RDONLY);
+    LOG_ALWAYS_FATAL_IF(fd == -1, "Failed to open file %s", fileName);
+    struct stat st = {};
+    LOG_ALWAYS_FATAL_IF(fstat(fd, &st) == -1, "Failed to stat file %s", fileName);
+    void* data = mmap(nullptr, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
+    sk_sp<SkData> skData =
+            SkData::MakeWithProc(data, st.st_size, unmap, reinterpret_cast<void*>(st.st_size));
+    std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(skData));
+    sk_sp<SkFontMgr> fm(SkFontMgr::RefDefault());
+    sk_sp<SkTypeface> typeface(fm->createFromStream(fontData.release()));
+    LOG_ALWAYS_FATAL_IF(typeface == nullptr, "Failed to make typeface from %s", fileName);
+    std::shared_ptr<minikin::MinikinFont> font = std::make_shared<MinikinFontSkia>(
+            std::move(typeface), data, st.st_size, 0, std::vector<minikin::FontVariation>());
+    return std::make_shared<minikin::FontFamily>(
+            std::vector<minikin::Font>({ minikin::Font(std::move(font), minikin::FontStyle()) }));
+}
+
+std::vector<std::shared_ptr<minikin::FontFamily>> makeSingleFamlyVector(const char* fileName) {
+    return std::vector<std::shared_ptr<minikin::FontFamily>>({ buildFamily(fileName) });
+}
+
+TEST(TypefaceTest, resolveDefault_and_setDefaultTest) {
+    std::unique_ptr<Typeface> regular(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(regular.get(), Typeface::resolveDefault(regular.get()));
+
+    Typeface* old = Typeface::resolveDefault(nullptr);  // Keep the original to restore it later.
+    ASSERT_NE(nullptr, old);
+
+    Typeface::setDefault(regular.get());
+    EXPECT_EQ(regular.get(), Typeface::resolveDefault(nullptr));
+
+    Typeface::setDefault(old);  // Restore to the original.
+}
+
+TEST(TypefaceTest, createWithDifferentBaseWeight) {
+    std::unique_ptr<Typeface> bold(Typeface::createWithDifferentBaseWeight(nullptr, 700));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, bold->fSkiaStyle);
+
+    std::unique_ptr<Typeface> light(Typeface::createWithDifferentBaseWeight(nullptr, 300));
+    EXPECT_EQ(3, light->fStyle.getWeight());
+    EXPECT_FALSE(light->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, light->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromRegular) {
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(nullptr, SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(nullptr, SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(nullptr, SkTypeface::kItalic));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.DEFAULT, Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface> boldItalic(
+            Typeface::createRelative(nullptr, SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_BoldBase) {
+    std::unique_ptr<Typeface> base(Typeface::createWithDifferentBaseWeight(nullptr, 700));
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(7, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(10, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(7, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-bold"), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(10, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_LightBase) {
+    std::unique_ptr<Typeface> base(Typeface::createWithDifferentBaseWeight(nullptr, 300));
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(3, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(6, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.ITLIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(3, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create("sans-serif-light"), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(6, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromBoldStyled) {
+    std::unique_ptr<Typeface> base(Typeface::createRelative(nullptr, SkTypeface::kBold));
+
+    // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.BOLD), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromItalicStyled) {
+    std::unique_ptr<Typeface> base(Typeface::createRelative(nullptr, SkTypeface::kItalic));
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java, Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // Typeface.create(Typeface.create(Typeface.DEFAULT, Typeface.ITALIC), Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createRelativeTest_fromSpecifiedStyled) {
+    std::unique_ptr<Typeface> base(Typeface::createAbsolute(nullptr, 400, false));
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.NORMAL);
+    std::unique_ptr<Typeface> normal(Typeface::createRelative(base.get(), SkTypeface::kNormal));
+    EXPECT_EQ(4, normal->fStyle.getWeight());
+    EXPECT_FALSE(normal->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, normal->fSkiaStyle);
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.BOLD);
+    std::unique_ptr<Typeface> bold(Typeface::createRelative(base.get(), SkTypeface::kBold));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.ITALIC);
+    std::unique_ptr<Typeface> italic(Typeface::createRelative(base.get(), SkTypeface::kItalic));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // Typeface typeface = new Typeface.Builder(invalid).setFallback("sans-serif")
+    //     .setWeight(700).setItalic(false).build();
+    // Typeface.create(typeface, Typeface.BOLD_ITALIC);
+    std::unique_ptr<Typeface>
+            boldItalic(Typeface::createRelative(base.get(), SkTypeface::kBoldItalic));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createAbsolute) {
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(false)
+    //     .build();
+    std::unique_ptr<Typeface> regular(Typeface::createAbsolute(nullptr, 400, false));
+    EXPECT_EQ(4, regular->fStyle.getWeight());
+    EXPECT_FALSE(regular->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, regular->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(false)
+    //     .build();
+    std::unique_ptr<Typeface> bold(Typeface::createAbsolute(nullptr, 700, false));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(400).setItalic(true)
+    //     .build();
+    std::unique_ptr<Typeface> italic(Typeface::createAbsolute(nullptr, 400, true));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(700).setItalic(true)
+    //     .build();
+    std::unique_ptr<Typeface> boldItalic(Typeface::createAbsolute(nullptr, 700, true));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBoldItalic, boldItalic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder(invalid).setFallback("sans-serif").setWeight(1100).setItalic(true)
+    //     .build();
+    std::unique_ptr<Typeface> over1000(Typeface::createAbsolute(nullptr, 1100, false));
+    EXPECT_EQ(10, over1000->fStyle.getWeight());
+    EXPECT_FALSE(over1000->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, over1000->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createFromFamilies_Single) {
+    // In Java, new Typeface.Builder("Roboto-Regular.ttf").setWeight(400).setItalic(false).build();
+    std::unique_ptr<Typeface> regular(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular), 400, false));
+    EXPECT_EQ(4, regular->fStyle.getWeight());
+    EXPECT_FALSE(regular->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, regular->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Bold.ttf").setWeight(700).setItalic(false).build();
+    std::unique_ptr<Typeface> bold(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 700, false));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Italic.ttf").setWeight(400).setItalic(true).build();
+    std::unique_ptr<Typeface> italic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoItalic), 400, true));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(700).setItalic(true).build();
+    std::unique_ptr<Typeface> boldItalic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic), 700, true));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java,
+    // new Typeface.Builder("Roboto-BoldItalic.ttf").setWeight(1100).setItalic(false).build();
+    std::unique_ptr<Typeface> over1000(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold), 1100, false));
+    EXPECT_EQ(10, over1000->fStyle.getWeight());
+    EXPECT_FALSE(over1000->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, over1000->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createFromFamilies_Single_resolveByTable) {
+    // In Java, new Typeface.Builder("Roboto-Regular.ttf").build();
+    std::unique_ptr<Typeface> regular(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoRegular),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(4, regular->fStyle.getWeight());
+    EXPECT_FALSE(regular->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kNormal, regular->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Bold.ttf").build();
+    std::unique_ptr<Typeface> bold(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBold),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(7, bold->fStyle.getWeight());
+    EXPECT_FALSE(bold->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kBold, bold->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-Italic.ttf").build();
+    std::unique_ptr<Typeface> italic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoItalic),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(4, italic->fStyle.getWeight());
+    EXPECT_TRUE(italic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+
+    // In Java, new Typeface.Builder("Roboto-BoldItalic.ttf").build();
+    std::unique_ptr<Typeface> boldItalic(
+            Typeface::createFromFamilies(makeSingleFamlyVector(kRobotoBoldItalic),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(7, boldItalic->fStyle.getWeight());
+    EXPECT_TRUE(boldItalic->fStyle.getItalic());
+    EXPECT_EQ(SkTypeface::kItalic, italic->fSkiaStyle);
+}
+
+TEST(TypefaceTest, createFromFamilies_Family) {
+    std::vector<std::shared_ptr<minikin::FontFamily>> families = {
+            buildFamily(kRobotoRegular), buildFamily(kRobotoBold), buildFamily(kRobotoItalic),
+            buildFamily(kRobotoBoldItalic)
+    };
+    std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(std::move(families),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(4, typeface->fStyle.getWeight());
+    EXPECT_FALSE(typeface->fStyle.getItalic());
+}
+
+TEST(TypefaceTest, createFromFamilies_Family_withoutRegular) {
+    std::vector<std::shared_ptr<minikin::FontFamily>> families = {
+            buildFamily(kRobotoBold), buildFamily(kRobotoItalic), buildFamily(kRobotoBoldItalic)
+    };
+    std::unique_ptr<Typeface> typeface(Typeface::createFromFamilies(std::move(families),
+                    RESOLVE_BY_FONT_TABLE, RESOLVE_BY_FONT_TABLE));
+    EXPECT_EQ(7, typeface->fStyle.getWeight());
+    EXPECT_FALSE(typeface->fStyle.getItalic());
+}
+
+}  // namespace
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index ccdf5ae..c78c99f 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -705,6 +705,8 @@
         }
 
         nativeDetachImage(image);
+        si.clearSurfacePlanes();
+        si.mPlanes = null;
         si.setDetached(true);
     }
 
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 349c9cb..2b7309f 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -359,28 +359,14 @@
             }
 
             ImageReader prevOwner = (ImageReader) image.getOwner();
-            // Only do the image attach for PRIVATE format images for now. Do the image
-            // copy for other formats. TODO: use attach for other formats to
-            // improve the performance, and fall back to copy when attach/detach
-            // fails. Right now, detach is guaranteed to fail as the buffer is
-            // locked when ImageReader#acquireNextImage is called. See bug 19962027.
-            if (image.getFormat() == ImageFormat.PRIVATE) {
-                prevOwner.detachImage(image);
-                attachAndQueueInputImage(image);
-                // This clears the native reference held by the original owner.
-                // When this Image is detached later by this ImageWriter, the
-                // native memory won't be leaked.
-                image.close();
-                return;
-            } else {
-                Image inputImage = dequeueInputImage();
-                inputImage.setTimestamp(image.getTimestamp());
-                inputImage.setCropRect(image.getCropRect());
-                ImageUtils.imageCopy(image, inputImage);
-                image.close();
-                image = inputImage;
-                ownedByMe = true;
-            }
+
+            prevOwner.detachImage(image);
+            attachAndQueueInputImage(image);
+            // This clears the native reference held by the original owner.
+            // When this Image is detached later by this ImageWriter, the
+            // native memory won't be leaked.
+            image.close();
+            return;
         }
 
         Rect crop = image.getCropRect();
diff --git a/media/java/android/media/soundtrigger/SoundTriggerDetector.java b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
index d5296ae..c091c84 100644
--- a/media/java/android/media/soundtrigger/SoundTriggerDetector.java
+++ b/media/java/android/media/soundtrigger/SoundTriggerDetector.java
@@ -137,7 +137,7 @@
         }
 
         /**
-         * Gets the raw audio that triggered the keyphrase.
+         * Gets the raw audio that triggered the detector.
          * This may be null if the trigger audio isn't available.
          * If non-null, the format of the audio can be obtained by calling
          * {@link #getCaptureAudioFormat()}.
@@ -154,6 +154,24 @@
         }
 
         /**
+         * Gets the opaque data passed from the detection engine for the event.
+         * This may be null if it was not populated by the engine, or if the data is known to
+         * contain the trigger audio.
+         *
+         * @see #getTriggerAudio
+         *
+         * @hide
+         */
+        @Nullable
+        public byte[] getData() {
+            if (!mTriggerAvailable) {
+                return mData;
+            } else {
+                return null;
+            }
+        }
+
+        /**
          * Gets the session ID to start a capture from the DSP.
          * This may be null if streaming capture isn't possible.
          * If non-null, the format of the audio that can be captured can be
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index 4496a82..e7da20b 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1453,7 +1453,8 @@
         /**
          * The release date of this TV program.
          *
-         * <p>The value should be in the form of either "yyyy-MM-dd" or "yyyy".
+         * <p>The value should be in one of the following formats:
+         * "yyyy", "yyyy-MM-dd", and "yyyy-MM-ddTHH:mm:ssZ" (UTC in ISO 8601).
          *
          * <p>Type: TEXT
          */
@@ -1624,7 +1625,12 @@
     /** Column definitions for the TV channels table. */
     public static final class Channels implements BaseTvColumns {
 
-        /** The content:// style URI for this table. */
+        /**
+         * The content:// style URI for this table.
+         *
+         * <p>SQL selection is not supported for {@link ContentResolver#query},
+         * {@link ContentResolver#update} and {@link ContentResolver#delete} operations.
+         */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
                 + PATH_CHANNEL);
 
@@ -2423,7 +2429,12 @@
      */
     public static final class Programs implements BaseTvColumns, ProgramColumns {
 
-        /** The content:// style URI for this table. */
+        /**
+         * The content:// style URI for this table.
+         *
+         * <p>SQL selection is not supported for {@link ContentResolver#query},
+         * {@link ContentResolver#update} and {@link ContentResolver#delete} operations.
+         */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
                 + PATH_PROGRAM);
 
@@ -2737,7 +2748,12 @@
      */
     public static final class RecordedPrograms implements BaseTvColumns, ProgramColumns {
 
-        /** The content:// style URI for this table. */
+        /**
+         * The content:// style URI for this table.
+         *
+         * <p>SQL selection is not supported for {@link ContentResolver#query},
+         * {@link ContentResolver#update} and {@link ContentResolver#delete} operations.
+         */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
                 + PATH_RECORDED_PROGRAM);
 
@@ -2858,7 +2874,12 @@
     public static final class PreviewPrograms implements BaseTvColumns, ProgramColumns,
         PreviewProgramColumns {
 
-        /** The content:// style URI for this table. */
+        /**
+         * The content:// style URI for this table.
+         *
+         * <p>SQL selection is not supported for {@link ContentResolver#query},
+         * {@link ContentResolver#update} and {@link ContentResolver#delete} operations.
+         */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
                 + PATH_PREVIEW_PROGRAM);
 
@@ -2905,7 +2926,12 @@
     public static final class WatchNextPrograms implements BaseTvColumns, ProgramColumns,
         PreviewProgramColumns {
 
-        /** The content:// style URI for this table. */
+        /**
+         * The content:// style URI for this table.
+         *
+         * <p>SQL selection is not supported for {@link ContentResolver#query},
+         * {@link ContentResolver#update} and {@link ContentResolver#delete} operations.
+         */
         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/"
                 + PATH_WATCH_NEXT_PROGRAM);
 
diff --git a/media/jni/android_media_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index ed5fbcf..b5ea632 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -499,30 +499,23 @@
 
     sp<Surface> surface = ctx->getProducer();
     status_t res = OK;
-    if (!isFormatOpaque(imageFormat)) {
-        // TODO: need implement, see b/19962027
-        jniThrowRuntimeException(env,
-                "nativeAttachImage for non-opaque image is not implement yet!!!");
-        return -1;
-    }
-
-    if (!isFormatOpaque(ctx->getBufferFormat())) {
+    if (isFormatOpaque(imageFormat) != isFormatOpaque(ctx->getBufferFormat())) {
         jniThrowException(env, "java/lang/IllegalStateException",
-                "Trying to attach an opaque image into a non-opaque ImageWriter");
+                "Trying to attach an opaque image into a non-opaque ImageWriter, or vice versa");
         return -1;
     }
 
     // Image is guaranteed to be from ImageReader at this point, so it is safe to
     // cast to BufferItem pointer.
-    BufferItem* opaqueBuffer = reinterpret_cast<BufferItem*>(nativeBuffer);
-    if (opaqueBuffer == NULL) {
+    BufferItem* buffer = reinterpret_cast<BufferItem*>(nativeBuffer);
+    if (buffer == NULL) {
         jniThrowException(env, "java/lang/IllegalStateException",
                 "Image is not initialized or already closed");
         return -1;
     }
 
     // Step 1. Attach Image
-    res = surface->attachBuffer(opaqueBuffer->mGraphicBuffer.get());
+    res = surface->attachBuffer(buffer->mGraphicBuffer.get());
     if (res != OK) {
         ALOGE("Attach image failed: %s (%d)", strerror(-res), res);
         switch (res) {
@@ -559,7 +552,7 @@
     }
 
     // Step 3. Queue Image.
-    res = anw->queueBuffer(anw.get(), opaqueBuffer->mGraphicBuffer.get(), /*fenceFd*/
+    res = anw->queueBuffer(anw.get(), buffer->mGraphicBuffer.get(), /*fenceFd*/
             -1);
     if (res != OK) {
         ALOGE("%s: Queue buffer failed: %s (%d)", __FUNCTION__, strerror(-res), res);
@@ -817,4 +810,3 @@
 
     return (ret1 || ret2);
 }
-
diff --git a/media/jni/soundpool/SoundPool.cpp b/media/jni/soundpool/SoundPool.cpp
index 87092d0..5f1cf16 100644
--- a/media/jni/soundpool/SoundPool.cpp
+++ b/media/jni/soundpool/SoundPool.cpp
@@ -30,9 +30,9 @@
 #include "SoundPool.h"
 #include "SoundPoolThread.h"
 #include <media/AudioPolicyHelper.h>
-#include <ndk/NdkMediaCodec.h>
-#include <ndk/NdkMediaExtractor.h>
-#include <ndk/NdkMediaFormat.h>
+#include <media/NdkMediaCodec.h>
+#include <media/NdkMediaExtractor.h>
+#include <media/NdkMediaFormat.h>
 
 namespace android
 {
diff --git a/native/android/Android.bp b/native/android/Android.bp
index eacda93..452adc0 100644
--- a/native/android/Android.bp
+++ b/native/android/Android.bp
@@ -19,3 +19,71 @@
     first_version: "9",
     unversioned_until: "current",
 }
+
+cc_defaults {
+    name: "libandroid_defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
+
+cc_library_shared {
+    name: "libandroid",
+    defaults: ["libandroid_defaults"],
+
+    srcs: [
+        "asset_manager.cpp",
+        "choreographer.cpp",
+        "configuration.cpp",
+        "hardware_buffer_jni.cpp",
+        "input.cpp",
+        "looper.cpp",
+        "native_activity.cpp",
+        "native_window_jni.cpp",
+        "net.c",
+        "obb.cpp",
+        "sensor.cpp",
+        "sharedmem.cpp",
+        "storage_manager.cpp",
+        "trace.cpp",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libcutils",
+        "libandroidfw",
+        "libinput",
+        "libutils",
+        "libbinder",
+        "libui",
+        "libgui",
+        "libsensor",
+        "libandroid_runtime",
+        "libnetd_client",
+    ],
+
+    static_libs: [
+        "libstorage",
+        "libarect",
+    ],
+
+    whole_static_libs: ["libnativewindow"],
+
+    export_static_lib_headers: ["libarect"],
+
+    include_dirs: ["bionic/libc/dns/include"],
+}
+
+// Network library.
+cc_library_shared {
+    name: "libandroid_net",
+    defaults: ["libandroid_defaults"],
+    srcs: ["net.c"],
+
+    shared_libs: ["libnetd_client"],
+
+    include_dirs: ["bionic/libc/dns/include"],
+}
diff --git a/native/android/Android.mk b/native/android/Android.mk
deleted file mode 100644
index 6e15331..0000000
--- a/native/android/Android.mk
+++ /dev/null
@@ -1,77 +0,0 @@
-BASE_PATH := $(call my-dir)
-LOCAL_PATH:= $(call my-dir)
-
-common_cflags := -Wall -Werror -Wunused -Wunreachable-code
-
-include $(CLEAR_VARS)
-
-# our source files
-#
-LOCAL_SRC_FILES:= \
-    asset_manager.cpp \
-    choreographer.cpp \
-    configuration.cpp \
-    hardware_buffer_jni.cpp \
-    input.cpp \
-    looper.cpp \
-    native_activity.cpp \
-    native_window_jni.cpp \
-    net.c \
-    obb.cpp \
-    sensor.cpp \
-    sharedmem.cpp \
-    storage_manager.cpp \
-    trace.cpp \
-
-LOCAL_SHARED_LIBRARIES := \
-    liblog \
-    libcutils \
-    libandroidfw \
-    libinput \
-    libutils \
-    libbinder \
-    libui \
-    libgui \
-    libsensor \
-    libandroid_runtime \
-    libnetd_client \
-
-LOCAL_STATIC_LIBRARIES := \
-    libstorage \
-    libarect \
-
-LOCAL_WHOLE_STATIC_LIBRARIES := \
-    libnativewindow
-
-LOCAL_C_INCLUDES += \
-    frameworks/base/native/include \
-    frameworks/base/core/jni/android \
-    bionic/libc/dns/include \
-    system/netd/include \
-
-LOCAL_EXPORT_STATIC_LIBRARY_HEADERS := \
-    libarect \
-    libnativewindow \
-
-LOCAL_MODULE := libandroid
-
-LOCAL_CFLAGS += $(common_cflags)
-
-include $(BUILD_SHARED_LIBRARY)
-
-# Network library.
-include $(CLEAR_VARS)
-LOCAL_MODULE := libandroid_net
-LOCAL_CFLAGS := $(common_cflags)
-LOCAL_SRC_FILES:= \
-    net.c \
-
-LOCAL_SHARED_LIBRARIES := \
-    libnetd_client \
-
-LOCAL_C_INCLUDES += \
-    frameworks/base/native/include \
-    bionic/libc/dns/include \
-    system/netd/include \
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/PrintSpooler/res/values-fr-rCA/strings.xml b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
index 9329d2a..8e12525 100644
--- a/packages/PrintSpooler/res/values-fr-rCA/strings.xml
+++ b/packages/PrintSpooler/res/values-fr-rCA/strings.xml
@@ -49,7 +49,7 @@
     <string name="print_options_collapsed" msgid="7455930445670414332">"Options d\'impression réduites"</string>
     <string name="search" msgid="5421724265322228497">"Rechercher"</string>
     <string name="all_printers_label" msgid="3178848870161526399">"Toutes les imprimantes"</string>
-    <string name="add_print_service_label" msgid="5356702546188981940">"Ajouter le service"</string>
+    <string name="add_print_service_label" msgid="5356702546188981940">"Ajouter un service"</string>
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Champ de recherche affiché"</string>
     <string name="print_search_box_hidden_utterance" msgid="5727755169343113351">"Champ de recherche masqué"</string>
     <string name="print_add_printer" msgid="1088656468360653455">"Ajouter une imprimante"</string>
diff --git a/packages/SettingsLib/res/layout/preference_two_target.xml b/packages/SettingsLib/res/layout/preference_two_target.xml
index 8f30d87..4c2583c 100644
--- a/packages/SettingsLib/res/layout/preference_two_target.xml
+++ b/packages/SettingsLib/res/layout/preference_two_target.xml
@@ -37,7 +37,7 @@
             android:id="@+id/icon_container"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:minWidth="60dp"
+            android:minWidth="56dp"
             android:orientation="horizontal"
             android:paddingEnd="12dp"
             android:paddingTop="4dp"
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index fcbb89d..70c6e47 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -203,7 +203,7 @@
     <string name="allow_mock_location" msgid="2787962564578664888">"Dozvoli lažne lokacije"</string>
     <string name="allow_mock_location_summary" msgid="317615105156345626">"Dozvoli lažne lokacije"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"Omogući proveru atributa za pregled"</string>
-    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Neka podaci za mobilne uređaje uvek budu aktivni, čak i kada je Wi‑Fi aktivan (radi brze promene mreže)."</string>
+    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Neka mobilni podaci uvek budu aktivni, čak i kada je Wi‑Fi aktivan (radi brze promene mreže)."</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"Dozvoli otklanjanje USB grešaka?"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"Otklanjanje USB grešaka namenjeno je samo za svrhe programiranja. Koristite ga za kopiranje podataka sa računara na uređaj i obrnuto, instaliranje aplikacija na uređaju bez obaveštenja i čitanje podataka iz evidencije."</string>
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"Želite li da opozovete pristup otklanjanju USB grešaka sa svih računara koje ste prethodno odobrili?"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 5891473..f851581 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -93,7 +93,7 @@
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Applications et utilisateurs supprimés"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"Partage de connexion par USB"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Point d\'accès Wi-Fi mobile"</string>
-    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Via Bluetooth"</string>
+    <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Par Bluetooth"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Partage de connexion"</string>
     <string name="tether_settings_title_all" msgid="8356136101061143841">"Partage de connexion"</string>
     <string name="managed_user_title" msgid="8109605045406748842">"Toutes les applis profess."</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 831515a..155f1c5 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -33,7 +33,7 @@
     <string name="wifi_no_internet" msgid="3880396223819116454">"Aucun accès à Internet"</string>
     <string name="saved_network" msgid="4352716707126620811">"Enregistré par <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Connecté automatiquement via %1$s"</string>
-    <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connecté automatiquement via un fournisseur d\'avis sur le réseau"</string>
+    <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Connecté automatiquement via un fournisseur d\'évaluation de l\'état du réseau"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Connecté via %1$s"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"Disponible via %1$s"</string>
     <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Connecté, aucun accès à Internet"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index e64e007..182d819 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -203,7 +203,7 @@
     <string name="allow_mock_location" msgid="2787962564578664888">"אפשר מיקומים מדומים"</string>
     <string name="allow_mock_location_summary" msgid="317615105156345626">"אפשר מיקומים מדומים"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"אפשר בדיקת תכונת תצוגה"</string>
-    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"‏השאר את הנתונים לנייד פעילים תמיד, גם כש-Wi‑Fi פעיל (למעבר מהיר בין רשתות)."</string>
+    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"‏השאר את חבילת הגלישה פעילה תמיד, גם כש-Wi‑Fi פעיל (למעבר מהיר בין רשתות)."</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"‏לאפשר ניפוי באגים של USB?"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"‏ניפוי באגים באמצעות USB מיועד למטרות פיתוח בלבד. השתמש בו להעתקת נתונים בין המחשב והמכשיר שלך, להתקנת אפליקציות במכשיר ללא התראה ולקריאת נתוני יומן."</string>
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"‏האם לבטל את הגישה לניפוי ב-USB מכל המחשבים שהענקת להם בעבר הרשאה?"</string>
@@ -253,7 +253,7 @@
     <string name="usb_audio_disable_routing" msgid="8114498436003102671">"‏השבת ניתוב אודיו ב-USB"</string>
     <string name="usb_audio_disable_routing_summary" msgid="980282760277312264">"‏השבת ניתוב אוטומטי אל התקני אודיו חיצוניים ב-USB"</string>
     <string name="debug_layout" msgid="5981361776594526155">"הצג את גבולות הפריסה"</string>
-    <string name="debug_layout_summary" msgid="2001775315258637682">"הצג גבולות קליפ, שוליים וכו\'"</string>
+    <string name="debug_layout_summary" msgid="2001775315258637682">"הצג גבולות אזור, שוליים וכדומה"</string>
     <string name="force_rtl_layout_all_locales" msgid="2259906643093138978">"אלץ כיוון פריסה מימין לשמאל"</string>
     <string name="force_rtl_layout_all_locales_summary" msgid="9192797796616132534">"אלץ כיוון פריסת מסך מימין לשמאל עבור כל השפות בכל המקומות"</string>
     <string name="force_hw_ui" msgid="6426383462520888732">"‏אלץ עיבוד ב-GPU"</string>
@@ -278,7 +278,7 @@
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"אפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string>
     <string name="enable_freeform_support" msgid="1461893351278940416">"הפעל את האפשרות לשנות את הגודל והמיקום של החלונות"</string>
     <string name="enable_freeform_support_summary" msgid="8247310463288834487">"הפעל תמיכה בתכונה הניסיונית של שינוי הגודל והמיקום של החלונות."</string>
-    <string name="local_backup_password_title" msgid="3860471654439418822">"סיסמת גיבוי מקומי"</string>
+    <string name="local_backup_password_title" msgid="3860471654439418822">"סיסמת גיבוי שולחן העבודה"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"גיבויים מלאים בשולחן העבודה אינם מוגנים כעת"</string>
     <string name="local_backup_password_summary_change" msgid="5376206246809190364">"הקש כדי לשנות או להסיר את הסיסמה לגיבויים מלאים בשולחן העבודה"</string>
     <string name="local_backup_password_toast_success" msgid="582016086228434290">"הוגדרה סיסמת גיבוי חדשה"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 97830f0..492f71d 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -33,7 +33,7 @@
     <string name="wifi_no_internet" msgid="3880396223819116454">"Интернетке туташпай турат"</string>
     <string name="saved_network" msgid="4352716707126620811">"<xliff:g id="NAME">%1$s</xliff:g> тарабынан сакталды"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"%1$s аркылуу автоматтык түрдө туташты"</string>
-    <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Тармак рейтингинин провайдери аркылуу автоматтык түрдө туташтырылды"</string>
+    <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Тармактардын рейтингинин автору аркылуу автоматтык түрдө туташты"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"%1$s аркылуу жеткиликтүү"</string>
     <string name="available_via_passpoint" msgid="1617440946846329613">"%1$s аркылуу жеткиликтүү"</string>
     <string name="wifi_connected_no_internet" msgid="3149853966840874992">"Туташып турат, Интернет жок"</string>
@@ -316,7 +316,7 @@
     <string name="daltonizer_mode_protanomaly" msgid="8424148009038666065">"Протаномалия (кызыл-жашыл)"</string>
     <string name="daltonizer_mode_tritanomaly" msgid="481725854987912389">"Тританомалия (көк-сары)"</string>
     <string name="accessibility_display_daltonizer_preference_title" msgid="5800761362678707872">"Түсүн тууралоо"</string>
-    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Бул сынамык мүмкүнчүлүк болгондуктан, иштин майнаптуулугуна таасир этиши мүмкүн."</string>
+    <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Бул сынамык мүмкүнчүлүк болгондуктан, түзмөктүн иштешине таасир этиши мүмкүн."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> менен алмаштырылган"</string>
     <string name="power_remaining_duration_only" msgid="845431008899029842">"Батарея түгөнгөнгө чейин калган убакыт: <xliff:g id="TIME">%1$s</xliff:g>"</string>
     <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"Батарея толгонго чейин калган убакыт: <xliff:g id="TIME">%1$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index c11fa9f..52840e3 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -165,7 +165,7 @@
     <string name="confirm_enable_oem_unlock_title" msgid="4802157344812385674">"OEM түгжээ тайлагчийг зөвшөөрөх үү?"</string>
     <string name="confirm_enable_oem_unlock_text" msgid="5517144575601647022">"АНХААР: Энэ тохиргоо асаалттай байгаа үед тухайн төхөөрөмжийн хамгаалалтын функцүүд ажиллахгүй."</string>
     <string name="mock_location_app" msgid="7966220972812881854">"Хуурамч байршлын апп сонгох"</string>
-    <string name="mock_location_app_not_set" msgid="809543285495344223">"Хуурамч байршлын апп-ыг тохируулаагүй байна"</string>
+    <string name="mock_location_app_not_set" msgid="809543285495344223">"Хуурамч байршлын аппыг тохируулаагүй байна"</string>
     <string name="mock_location_app_set" msgid="8966420655295102685">"Хуурамч байршлын апп: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="debug_networking_category" msgid="7044075693643009662">"Сүлжээ"</string>
     <string name="wifi_display_certification" msgid="8611569543791307533">"Утасгүй дэлгэцийн сертификат"</string>
@@ -233,7 +233,7 @@
     <string name="media_category" msgid="4388305075496848353">"Медиа"</string>
     <string name="debug_monitoring_category" msgid="7640508148375798343">"Мониторинг"</string>
     <string name="strict_mode" msgid="1938795874357830695">"Хатуу горимыг идэвхжүүлсэн"</string>
-    <string name="strict_mode_summary" msgid="142834318897332338">"Апп-ууд үндсэн хэлхээс дээр удаан хугацаанд үйлдлүүд хийх үед дэлгэцийг анивчуулах"</string>
+    <string name="strict_mode_summary" msgid="142834318897332338">"Аппууд үндсэн хэлхээс дээр удаан хугацаанд үйлдлүүд хийх үед дэлгэцийг анивчуулах"</string>
     <string name="pointer_location" msgid="6084434787496938001">"Чиглүүлэгчийн байршил"</string>
     <string name="pointer_location_summary" msgid="840819275172753713">"Дэлгэцийн давхаргаар одоогийн хүрэлтийн өгөгдлийг харуулж байна"</string>
     <string name="show_touches" msgid="2642976305235070316">"Товшилтыг харуулах"</string>
@@ -272,7 +272,7 @@
     <string name="app_process_limit_title" msgid="4280600650253107163">"Далд процессын хязгаар"</string>
     <string name="show_all_anrs" msgid="28462979638729082">"Бүх ANRs харуулах"</string>
     <string name="show_all_anrs_summary" msgid="641908614413544127">"Далд апп-уудад Апп Хариу Өгөхгүй байна гэснийг харуулах"</string>
-    <string name="force_allow_on_external" msgid="3215759785081916381">"Апп-ыг гадаад санах ойд хадгалахыг зөвшөөрөх"</string>
+    <string name="force_allow_on_external" msgid="3215759785081916381">"Аппыг гадаад санах ойд хадгалахыг зөвшөөрөх"</string>
     <string name="force_allow_on_external_summary" msgid="3640752408258034689">"Манифест утгыг нь үл хамааран дурын апп-г гадаад санах ойд бичих боломжтой болгодог"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string>
     <string name="force_resizable_activities_summary" msgid="6667493494706124459">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааны хэмжээг олон цонхонд өөрчилж болохуйц болгоно уу."</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index ac7d7de..1e55e15 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -167,7 +167,7 @@
     <string name="mock_location_app" msgid="7966220972812881854">"ਮੌਕ ਸਥਾਨ ਐਪ ਚੁਣੋ"</string>
     <string name="mock_location_app_not_set" msgid="809543285495344223">"ਕੋਈ ਵੀ ਮੌਕ ਸਥਾਨ ਐਪ ਸੈੱਟ ਨਹੀਂ ਕੀਤੀ ਗਈ"</string>
     <string name="mock_location_app_set" msgid="8966420655295102685">"ਮੌਕ ਸਥਾਨ ਐਪ: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-    <string name="debug_networking_category" msgid="7044075693643009662">"ਨੈਟਵਰਕਿੰਗ"</string>
+    <string name="debug_networking_category" msgid="7044075693643009662">"ਨੈੱਟਵਰਕਿੰਗ"</string>
     <string name="wifi_display_certification" msgid="8611569543791307533">"ਵਾਇਰਲੈਸ ਡਿਸਪਲੇ ਪ੍ਰਮਾਣੀਕਰਨ"</string>
     <string name="wifi_verbose_logging" msgid="4203729756047242344">"Wi‑Fi ਵਰਬੋਸ ਲੌਗਿੰਗ ਸਮਰੱਥ ਬਣਾਓ"</string>
     <string name="wifi_aggressive_handover" msgid="5309131983693661320">"ਆਕਰਮਣਸ਼ੀਲ Wi‑Fi ਤੋਂ ਮੋਬਾਈਲ ਹੈਂਡਓਵਰ"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index a8f5566..75b766b 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -31,7 +31,7 @@
     <string name="wifi_not_in_range" msgid="1136191511238508967">"Mimo dosah"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"Nedôjde k automatickému pripojeniu"</string>
     <string name="wifi_no_internet" msgid="3880396223819116454">"Žiadny prístup k internetu"</string>
-    <string name="saved_network" msgid="4352716707126620811">"Uložil(a) <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="saved_network" msgid="4352716707126620811">"Uložila aplikácia <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"Automaticky pripojené prostredníctvom %1$s"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"Automaticky pripojené prostredníctvom poskytovateľa hodnotenia siete"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"Pripojené prostredníctvom %1$s"</string>
@@ -91,7 +91,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"OS Android"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"Odstránené aplikácie"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"Odstránené aplikácie a používatelia"</string>
-    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Zdieľané pripojenie cez USB"</string>
+    <string name="tether_settings_title_usb" msgid="6688416425801386511">"Pripojenie cez USB"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"Prenosný prístupový bod"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"Pripojenie cez Bluetooth"</string>
     <string name="tether_settings_title_usb_bluetooth" msgid="5355828977109785001">"Zdieľané pripojenie"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 3992dbe..15ba747 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -203,7 +203,7 @@
     <string name="allow_mock_location" msgid="2787962564578664888">"Дозволи лажне локације"</string>
     <string name="allow_mock_location_summary" msgid="317615105156345626">"Дозволи лажне локације"</string>
     <string name="debug_view_attributes" msgid="6485448367803310384">"Омогући проверу атрибута за преглед"</string>
-    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Нека подаци за мобилне уређаје увек буду активни, чак и када је Wi‑Fi активан (ради брзе промене мреже)."</string>
+    <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Нека мобилни подаци увек буду активни, чак и када је Wi‑Fi активан (ради брзе промене мреже)."</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"Дозволи отклањање USB грешака?"</string>
     <string name="adb_warning_message" msgid="7316799925425402244">"Отклањање USB грешака намењено је само за сврхе програмирања. Користите га за копирање података са рачунара на уређај и обрнуто, инсталирање апликација на уређају без обавештења и читање података из евиденције."</string>
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"Желите ли да опозовете приступ отклањању USB грешака са свих рачунара које сте претходно одобрили?"</string>
diff --git a/packages/SettingsLib/res/values-uz/arrays.xml b/packages/SettingsLib/res/values-uz/arrays.xml
index cc7ef9b..1d4e1e9 100644
--- a/packages/SettingsLib/res/values-uz/arrays.xml
+++ b/packages/SettingsLib/res/values-uz/arrays.xml
@@ -22,7 +22,7 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
   <string-array name="wifi_status">
     <item msgid="1922181315419294640"></item>
-    <item msgid="8934131797783724664">"Tekshirib chiqilmoqda…"</item>
+    <item msgid="8934131797783724664">"Qidiruv…"</item>
     <item msgid="8513729475867537913">"Ulanmoqda…"</item>
     <item msgid="515055375277271756">"Tasdiqdan o‘tilmoqda…"</item>
     <item msgid="1943354004029184381">"IP manzil o‘zlashtirilmoqda…"</item>
@@ -36,7 +36,7 @@
   </string-array>
   <string-array name="wifi_status_with_ssid">
     <item msgid="7714855332363650812"></item>
-    <item msgid="8878186979715711006">"Tekshirilmoqda…"</item>
+    <item msgid="8878186979715711006">"Qidiruv…"</item>
     <item msgid="355508996603873860">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> tarmog‘iga ulanilmoqda…"</item>
     <item msgid="554971459996405634">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> bilan aloqa o‘rnatilyapti…"</item>
     <item msgid="7928343808033020343">"<xliff:g id="NETWORK_NAME">%1$s</xliff:g> IP manzil beryapti…"</item>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 43d75b3b..ac7cd4e 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -31,7 +31,7 @@
     <string name="wifi_not_in_range" msgid="1136191511238508967">"不在范围内"</string>
     <string name="wifi_no_internet_no_reconnect" msgid="5724903347310541706">"无法自动连接"</string>
     <string name="wifi_no_internet" msgid="3880396223819116454">"无法连接到互联网"</string>
-    <string name="saved_network" msgid="4352716707126620811">"已通过<xliff:g id="NAME">%1$s</xliff:g>保存"</string>
+    <string name="saved_network" msgid="4352716707126620811">"由<xliff:g id="NAME">%1$s</xliff:g>保存"</string>
     <string name="connected_via_network_scorer" msgid="5713793306870815341">"已通过%1$s自动连接"</string>
     <string name="connected_via_network_scorer_default" msgid="7867260222020343104">"已自动连接(通过网络评分服务提供方)"</string>
     <string name="connected_via_passpoint" msgid="2826205693803088747">"已通过%1$s连接"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java b/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java
new file mode 100644
index 0000000..766c42b
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/SecureTouchListener.java
@@ -0,0 +1,44 @@
+package com.android.settingslib;
+
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.view.View;
+import android.widget.Toast;
+
+/**
+ * A touch listener which consumes touches when another window is partly or wholly obscuring the
+ * window containing the view this listener is attached to.
+ * Optionally accepts a string to show the user as a toast when consuming an insecure touch
+ */
+public class SecureTouchListener implements View.OnTouchListener {
+
+    private static final long TAP_DEBOUNCE_TIME = 2000;
+    private long mLastToastTime = 0;
+    private String mWarningText;
+
+    public SecureTouchListener() {
+        this(null);
+    }
+
+    public SecureTouchListener(String warningText) {
+        mWarningText = warningText;
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        if ((event.getFlags() & MotionEvent.FLAG_WINDOW_IS_OBSCURED) != 0
+                || (event.getFlags() & MotionEvent.FLAG_WINDOW_IS_PARTIALLY_OBSCURED) != 0) {
+            if (mWarningText != null) {
+                // Show a toast warning the user
+                final long currentTime = SystemClock.uptimeMillis();
+                if (currentTime - mLastToastTime > TAP_DEBOUNCE_TIME) {
+                    mLastToastTime = currentTime;
+                    Toast.makeText(v.getContext(), mWarningText, Toast.LENGTH_SHORT).show();
+                }
+            }
+            // Consume the touch event
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
index 151e0ea..abbef70 100644
--- a/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
+++ b/packages/SettingsLib/src/com/android/settingslib/TetherUtil.java
@@ -17,13 +17,19 @@
 
 import android.content.Context;
 import android.os.SystemProperties;
+import android.support.annotation.VisibleForTesting;
 import android.telephony.CarrierConfigManager;
 
 public class TetherUtil {
 
-    private static boolean isEntitlementCheckRequired(Context context) {
+    @VisibleForTesting
+    static boolean isEntitlementCheckRequired(Context context) {
         final CarrierConfigManager configManager = (CarrierConfigManager) context
              .getSystemService(Context.CARRIER_CONFIG_SERVICE);
+        if (configManager == null || configManager.getConfig() == null) {
+            // return service default
+            return true;
+        }
         return configManager.getConfig().getBoolean(CarrierConfigManager
              .KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
index ea28fe6..5a57e69 100644
--- a/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
+++ b/packages/SettingsLib/src/com/android/settingslib/deviceinfo/StorageMeasurement.java
@@ -152,6 +152,12 @@
         final MeasurementDetails details = new MeasurementDetails();
         if (mVolume == null) return details;
 
+        if (mVolume.getType() == VolumeInfo.TYPE_PUBLIC) {
+            details.totalSize = mVolume.getPath().getTotalSpace();
+            details.availSize = mVolume.getPath().getUsableSpace();
+            return details;
+        }
+
         try {
             details.totalSize = mStats.getTotalBytes(mVolume.fsUuid);
             details.availSize = mStats.getFreeBytes(mVolume.fsUuid);
@@ -161,7 +167,6 @@
             return details;
         }
 
-
         final long finishTotal = SystemClock.elapsedRealtime();
         Log.d(TAG, "Measured total storage in " + (finishTotal - start) + "ms");
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 5a178a5..eb513e1 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -998,7 +998,8 @@
             if (mRssi != info.getRssi()) {
                 mRssi = info.getRssi();
                 updated = true;
-            } else if (mNetworkInfo.getDetailedState() != networkInfo.getDetailedState()) {
+            } else if (mNetworkInfo != null && networkInfo != null
+                    && mNetworkInfo.getDetailedState() != networkInfo.getDetailedState()) {
                 updated = true;
             }
             mInfo = info;
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
index f519a90..d4ce40c 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/wifi/WifiTrackerTest.java
@@ -465,9 +465,9 @@
     private void updateScoresAndWaitForAccessPointsChangedCallback() throws InterruptedException {
         // Updating scores can happen together or one after the other, so the latch countdown is set
         // to 2.
-        mAccessPointsChangedLatch = new CountDownLatch(3);
+        mAccessPointsChangedLatch = new CountDownLatch(2);
         updateScores();
-        assertTrue("onAccessPointChanged was not called three times",
+        assertTrue("onAccessPointChanged was not called twice",
             mAccessPointsChangedLatch.await(LATCH_TIMEOUT, TimeUnit.MILLISECONDS));
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java
new file mode 100644
index 0000000..3b1c3ac
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/TetherUtilTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib;
+
+
+import android.content.Context;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.annotation.Config;
+
+import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.Mockito.when;
+
+@RunWith(SettingLibRobolectricTestRunner.class)
+@Config(manifest = TestConfig.MANIFEST_PATH, sdk = TestConfig.SDK_VERSION)
+public class TetherUtilTest {
+
+    @Mock
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void isEntitlementCheckRequired_noConfigManager_returnTrue() {
+        when(mContext.getSystemService(Context.CARRIER_CONFIG_SERVICE)).thenReturn(null);
+
+        assertThat(TetherUtil.isEntitlementCheckRequired(mContext)).isTrue();
+    }
+}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 885573e..f475361 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -696,6 +696,12 @@
                 Settings.Global.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX,
                 GlobalSettingsProto.BLUETOOTH_A2DP_SRC_PRIORITY_PREFIX);
         dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_A2DP_SUPPORTS_OPTIONAL_CODECS_PREFIX);
+        dumpSetting(s, p,
+                Settings.Global.BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX,
+                GlobalSettingsProto.BLUETOOTH_A2DP_OPTIONAL_CODECS_ENABLED_PREFIX);
+        dumpSetting(s, p,
                 Settings.Global.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX,
                 GlobalSettingsProto.BLUETOOTH_INPUT_DEVICE_PRIORITY_PREFIX);
         dumpSetting(s, p,
@@ -979,9 +985,6 @@
                 Settings.Secure.AUTOFILL_SERVICE,
                 SecureSettingsProto.AUTOFILL_SERVICE);
         dumpSetting(s, p,
-                Settings.Secure.BLUETOOTH_HCI_LOG,
-                SecureSettingsProto.BLUETOOTH_HCI_LOG);
-        dumpSetting(s, p,
                 Settings.Secure.USER_SETUP_COMPLETE,
                 SecureSettingsProto.USER_SETUP_COMPLETE);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 4b304b2..14e2a85 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1142,28 +1142,55 @@
         } finally {
             Binder.restoreCallingIdentity(token);
         }
+
+        final SettingsState ssaidSettings = mSettingsRegistry.getSettingsLocked(
+                SETTINGS_TYPE_SSAID, owningUserId);
+
         if (instantSsaid != null) {
             // Use the stored value if it is still valid.
             if (ssaid != null && instantSsaid.equals(ssaid.getValue())) {
-                return ssaid;
+                return mascaradeSsaidSetting(ssaidSettings, ssaid);
             }
             // The value has changed, update the stored value.
-            final SettingsState ssaidSettings = mSettingsRegistry.getSettingsLocked(
-                    SETTINGS_TYPE_SSAID, owningUserId);
             final boolean success = ssaidSettings.insertSettingLocked(name, instantSsaid, null,
                     true, callingPkg.packageName);
             if (!success) {
                 throw new IllegalStateException("Failed to update instant app android id");
             }
-            return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId, name);
+            Setting setting = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID,
+                    owningUserId, name);
+            return mascaradeSsaidSetting(ssaidSettings, setting);
         }
 
         // Lazy initialize ssaid if not yet present in ssaid table.
         if (ssaid == null || ssaid.isNull() || ssaid.getValue() == null) {
-            return mSettingsRegistry.generateSsaidLocked(callingPkg, owningUserId);
+            Setting setting = mSettingsRegistry.generateSsaidLocked(callingPkg, owningUserId);
+            return mascaradeSsaidSetting(ssaidSettings, setting);
         }
 
-        return ssaid;
+        return mascaradeSsaidSetting(ssaidSettings, ssaid);
+    }
+
+    private Setting mascaradeSsaidSetting(SettingsState settingsState, Setting ssaidSetting) {
+        // SSAID settings are located in a dedicated table for internal bookkeeping
+        // but for the world they reside in the secure table, so adjust the key here.
+        // We have a special name when looking it up but want the world to see it as
+        // "android_id".
+        if (ssaidSetting != null) {
+            return settingsState.new Setting(ssaidSetting) {
+                @Override
+                public int getKey() {
+                    final int userId = getUserIdFromKey(super.getKey());
+                    return makeKey(SETTINGS_TYPE_SECURE, userId);
+                }
+
+                @Override
+                public String getName() {
+                    return Settings.Secure.ANDROID_ID;
+                }
+            };
+        }
+        return null;
     }
 
     private boolean insertSecureSetting(String name, String value, String tag,
@@ -1173,7 +1200,6 @@
                     + ", " + tag  + ", " + makeDefault + ", "  + requestingUserId
                     + ", " + forceNotify + ")");
         }
-
         return mutateSecureSetting(name, value, tag, makeDefault, requestingUserId,
                 MUTATION_OPERATION_INSERT, forceNotify, 0);
     }
@@ -1879,6 +1905,7 @@
         Bundle result = new Bundle();
         result.putString(Settings.NameValueTable.VALUE,
                 !setting.isNull() ? setting.getValue() : null);
+
         mSettingsRegistry.mGenerationRegistry.addGenerationData(result, setting.getKey());
         return result;
     }
diff --git a/packages/Shell/res/values-hy/strings.xml b/packages/Shell/res/values-hy/strings.xml
index 5d7f294..cd57e76 100644
--- a/packages/Shell/res/values-hy/strings.xml
+++ b/packages/Shell/res/values-hy/strings.xml
@@ -16,7 +16,7 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_label" msgid="3701846017049540910">"Խեցի"</string>
+    <string name="app_label" msgid="3701846017049540910">"Shell"</string>
     <string name="bugreport_notification_channel" msgid="2574150205913861141">"Վրիպակների հաշվետվություններ"</string>
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցը ստեղծվում է"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցը գրանցվեց"</string>
diff --git a/packages/Shell/res/values-in/strings.xml b/packages/Shell/res/values-in/strings.xml
index dc86065..5c5ba816 100644
--- a/packages/Shell/res/values-in/strings.xml
+++ b/packages/Shell/res/values-in/strings.xml
@@ -26,8 +26,8 @@
     <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Pilih untuk membagikan laporan bug Anda"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Ketuk untuk membagikan laporan bug"</string>
     <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"Pilih untuk membagikan laporan bug tanpa screenshot atau menunggu screenshot selesai"</string>
-    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Ketuk untuk membagikan laporan bug tanpa tangkapan layar atau menunggu tangkapan layar selesai"</string>
-    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Ketuk untuk membagikan laporan bug tanpa tangkapan layar atau menunggu tangkapan layar selesai"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"Ketuk untuk membagikan laporan bug tanpa screenshot atau menunggu screenshot selesai"</string>
+    <string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"Ketuk untuk membagikan laporan bug tanpa screenshot atau menunggu screenshot selesai"</string>
     <string name="bugreport_confirm" msgid="5917407234515812495">"Laporan bug berisi data dari berbagai file log sistem, yang mungkin mencakup data yang dianggap sensitif (seperti data penggunaan aplikasi dan lokasi). Hanya bagikan laporan bug dengan aplikasi dan orang yang Anda percaya."</string>
     <string name="bugreport_confirm_dont_repeat" msgid="6179945398364357318">"Jangan tampilkan lagi"</string>
     <string name="bugreport_storage_title" msgid="5332488144740527109">"Laporan bug"</string>
@@ -35,9 +35,9 @@
     <string name="bugreport_add_details_to_zip_failed" msgid="1302931926486712371">"Tidak dapat menambahkan detail laporan bug ke file zip"</string>
     <string name="bugreport_unnamed" msgid="2800582406842092709">"tanpa nama"</string>
     <string name="bugreport_info_action" msgid="2158204228510576227">"Detail"</string>
-    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Tangkapan layar"</string>
-    <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Tangkapan layar berhasil diambil."</string>
-    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan layar tidak dapat diambil."</string>
+    <string name="bugreport_screenshot_action" msgid="8677781721940614995">"Screenshot"</string>
+    <string name="bugreport_screenshot_taken" msgid="5684211273096253120">"Screenshot berhasil diambil."</string>
+    <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot tidak dapat diambil."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detail laporan bug <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nama file"</string>
     <string name="bugreport_info_title" msgid="2306030793918239804">"Judul bug"</string>
diff --git a/packages/SystemUI/Android.mk b/packages/SystemUI/Android.mk
index c7bae66..8fa217d 100644
--- a/packages/SystemUI/Android.mk
+++ b/packages/SystemUI/Android.mk
@@ -31,6 +31,7 @@
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
     SystemUIPluginLib \
+    android-support-v4 \
     android-support-v7-recyclerview \
     android-support-v7-preference \
     android-support-v7-appcompat \
diff --git a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/drawable/GradientDrawable.java b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/drawable/GradientDrawable.java
index e046fb3..e75d95a 100644
--- a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/drawable/GradientDrawable.java
+++ b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/drawable/GradientDrawable.java
@@ -171,7 +171,7 @@
         // (avoiding banding) by merging the background solid color into
         // the gradient directly
         RadialGradient radialGradient = new RadialGradient(x, y, radius,
-                mMainColor, mSecondaryColor, Shader.TileMode.CLAMP);
+                mSecondaryColor, mMainColor, Shader.TileMode.CLAMP);
         mPaint.setShader(radialGradient);
     }
 
diff --git a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java
index a7b2b99..b2d595a 100644
--- a/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java
+++ b/packages/SystemUI/colorextraction/src/com/google/android/colorextraction/types/Tonal.java
@@ -87,7 +87,6 @@
                 hsl);
         hsl[0] /= 360.0f; // normalize
 
-        // TODO, we're finding a tonal palette for a hue, not all components
         TonalPalette palette = findTonalPalette(hsl[0]);
 
         // Fall back to population sort if we couldn't find a tonal palette
@@ -106,15 +105,17 @@
         float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f);
         float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f);
 
+        final int firstColorIndex = fitIndex;
+        final int secondColorIndex = Math.min(fitIndex + 2, h.length - 1);
 
-        hsl[0] = fract(h[0]) * 360.0f;
-        hsl[1] = s[0];
-        hsl[2] = l[0];
+        hsl[0] = fract(h[firstColorIndex]) * 360.0f;
+        hsl[1] = s[firstColorIndex];
+        hsl[2] = l[firstColorIndex];
         gradientColors.setMainColor(ColorUtils.HSLToColor(hsl));
 
-        hsl[0] = fract(h[1]) * 360.0f;
-        hsl[1] = s[1];
-        hsl[2] = l[1];
+        hsl[0] = fract(h[secondColorIndex]) * 360.0f;
+        hsl[1] = s[secondColorIndex];
+        hsl[2] = l[secondColorIndex];
         gradientColors.setSecondaryColor(ColorUtils.HSLToColor(hsl));
     }
 
@@ -257,43 +258,283 @@
 
     // Data definition of Material Design tonal palettes
     // When the sort type is set to TONAL, these palettes are used to find
-    // a best fist. Each palette is defined as 10 HSL colors
+    // a best fit. Each palette is defined as 22 HSL colors
     private static final TonalPalette[] TONAL_PALETTES = {
-            // Orange
             new TonalPalette(
-                    new float[] { 0.028f, 0.042f, 0.053f, 0.061f, 0.078f, 0.1f, 0.111f, 0.111f, 0.111f, 0.111f },
-                    new float[] { 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f },
-                    new float[] { 0.5f, 0.53f, 0.54f, 0.55f, 0.535f, 0.52f, 0.5f, 0.63f, 0.75f, 0.85f }
+                    new float[]{0, 0.991f, 1, 0.9833333333333333f, 2, 0f, 3, 0f, 4, 0f, 5,
+                            0.01134380453752181f, 6, 0.015625000000000003f, 7,
+                            0.024193548387096798f,
+                            8, 0.027397260273972573f, 9, 0.017543859649122865f},
+                    new float[]{0, 1f, 1, 1f, 2, 1f, 3, 1f, 4, 0.8434782608695652f, 5, 1f, 6, 1f, 7,
+                            1f, 8, 1f, 9, 1f},
+                    new float[]{0, 0.2f, 1, 0.27450980392156865f, 2, 0.34901960784313724f, 3,
+                            0.4235294117647059f, 4, 0.5490196078431373f, 5, 0.6254901960784314f, 6,
+                            0.6862745098039216f, 7, 0.7568627450980392f, 8, 0.8568627450980393f, 9,
+                            0.9254901960784314f}
             ),
-            // Yellow
             new TonalPalette(
-                    new float[] { 0.111f, 0.111f, 0.125f, 0.133f, 0.139f, 0.147f, 0.156f, 0.156f, 0.156f, 0.156f },
-                    new float[] { 1f, 0.942f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f },
-                    new float[] { 0.43f, 0.484f, 0.535f, 0.555f, 0.57f, 0.575f, 0.595f, 0.715f, 0.78f, 0.885f }
+                    new float[]{0, 0.6385767790262171f, 1, 0.6301169590643275f, 2,
+                            0.6223958333333334f, 3, 0.6151079136690647f, 4, 0.6065400843881856f, 5,
+                            0.5986964618249534f, 6, 0.5910746812386157f, 7, 0.5833333333333334f, 8,
+                            0.5748031496062993f, 9, 0.5582010582010583f},
+                    new float[]{0, 1f, 1, 1f, 2, 0.9014084507042253f, 3, 0.8128654970760234f, 4,
+                            0.7979797979797981f, 5, 0.7816593886462883f, 6, 0.778723404255319f, 7,
+                            1f, 8, 1f, 9, 1f},
+                    new float[]{0, 0.17450980392156862f, 1, 0.2235294117647059f, 2,
+                            0.2784313725490196f, 3, 0.3352941176470588f, 4, 0.388235294117647f, 5,
+                            0.44901960784313727f, 6, 0.5392156862745098f, 7, 0.6509803921568628f, 8,
+                            0.7509803921568627f, 9, 0.8764705882352941f}
             ),
-            // Green
             new TonalPalette(
-                    new float[] { 0.325f, 0.336f, 0.353f, 0.353f, 0.356f, 0.356f, 0.356f, 0.356f, 0.356f, 0.356f },
-                    new float[] { 1f, 1f, 0.852f, 0.754f, 0.639f, 0.667f, 0.379f, 0.542f, 1f, 1f },
-                    new float[] { 0.06f, 0.1f, 0.151f, 0.194f, 0.25f, 0.312f, 0.486f, 0.651f, 0.825f, 0.885f }
+                    new float[]{0, 0.5669934640522876f, 1, 0.5748031496062993f, 2,
+                            0.5595238095238095f, 3, 0.5473118279569893f, 4, 0.5393258426966292f, 5,
+                            0.5315955766192734f, 6, 0.524031007751938f, 7, 0.5154711673699016f, 8,
+                            0.508080808080808f, 9, 0.5f},
+                    new float[]{0, 1f, 1, 1f, 2, 1f, 3, 1f, 4, 1f, 5, 1f, 6, 0.8847736625514403f, 7,
+                            1f, 8, 1f, 9, 1f},
+                    new float[]{0, 0.2f, 1, 0.24901960784313726f, 2, 0.27450980392156865f, 3,
+                            0.30392156862745096f, 4, 0.34901960784313724f, 5, 0.4137254901960784f,
+                            6, 0.47647058823529415f, 7, 0.5352941176470588f, 8, 0.6764705882352942f,
+                            9, 0.8f}
             ),
-            // Blue
             new TonalPalette(
-                    new float[] { 0.631f, 0.603f, 0.592f, 0.586f, 0.572f, 0.544f, 0.519f, 0.519f, 0.519f, 0.519f },
-                    new float[] { 0.852f, 1f, 0.887f, 0.852f, 0.871f, 0.907f, 0.949f, 0.934f, 0.903f, 0.815f },
-                    new float[] { 0.34f, 0.38f, 0.482f, 0.497f, 0.536f, 0.571f, 0.608f, 0.696f, 0.794f, 0.892f }
+                    new float[]{0, 0.5082304526748972f, 1, 0.5069444444444444f, 2, 0.5f, 3, 0.5f, 4,
+                            0.5f, 5, 0.48724954462659376f, 6, 0.4800347222222222f, 7,
+                            0.4755134281200632f, 8, 0.4724409448818897f, 9, 0.4671052631578947f},
+                    new float[]{0, 1f, 1, 0.8888888888888887f, 2, 0.9242424242424242f, 3, 1f, 4, 1f,
+                            5, 0.8133333333333332f, 6, 0.7868852459016393f, 7, 1f, 8, 1f, 9, 1f},
+                    new float[]{0, 0.1588235294117647f, 1, 0.21176470588235297f, 2,
+                            0.25882352941176473f, 3, 0.3f, 4, 0.34901960784313724f, 5,
+                            0.44117647058823534f, 6, 0.5215686274509804f, 7, 0.5862745098039216f, 8,
+                            0.7509803921568627f, 9, 0.8509803921568627f}
             ),
-            // Purple
             new TonalPalette(
-                    new float[] { 0.839f, 0.831f, 0.825f, 0.819f, 0.803f, 0.803f, 0.772f, 0.772f, 0.772f, 0.772f },
-                    new float[] { 1f, 1f, 1f, 1f, 1f, 1f, 0.769f, 0.701f, 0.612f, 0.403f },
-                    new float[] { 0.125f, 0.15f, 0.2f, 0.245f, 0.31f, 0.36f, 0.567f, 0.666f, 0.743f, 0.833f }
+                    new float[]{0, 0.3333333333333333f, 1, 0.3333333333333333f, 2,
+                            0.34006734006734f, 3, 0.34006734006734f, 4, 0.34006734006734f, 5,
+                            0.34259259259259256f, 6, 0.3475783475783476f, 7, 0.34767025089605735f,
+                            8, 0.3467741935483871f, 9, 0.3703703703703704f},
+                    new float[]{0, 0.6703296703296703f, 1, 0.728813559322034f, 2,
+                            0.5657142857142856f, 3, 0.5076923076923077f, 4, 0.3944223107569721f, 5,
+                            0.6206896551724138f, 6, 0.8931297709923666f, 7, 1f, 8, 1f, 9, 1f},
+                    new float[]{0, 0.1784313725490196f, 1, 0.23137254901960785f, 2,
+                            0.3431372549019608f, 3, 0.38235294117647056f, 4, 0.49215686274509807f,
+                            5, 0.6588235294117647f, 6, 0.7431372549019608f, 7, 0.8176470588235294f,
+                            8, 0.8784313725490196f, 9, 0.9294117647058824f}
             ),
-            // Red
             new TonalPalette(
-                    new float[] { 0.964f, 0.975f, 0.975f, 0.975f, 0.972f, 0.992f, 1.003f, 1.011f, 1.011f, 1.011f },
-                    new float[] { 0.869f, 0.802f, 0.739f, 0.903f, 1f, 1f, 1f, 1f, 1f, 1f },
-                    new float[] { 0.241f, 0.316f, 0.46f, 0.586f, 0.655f, 0.7f, 0.75f, 0.8f, 0.84f, 0.88f }
+                    new float[]{0, 0.162280701754386f, 1, 0.15032679738562088f, 2,
+                            0.15879265091863518f, 3, 0.16236559139784948f, 4, 0.17443868739205526f,
+                            5, 0.17824074074074076f, 6, 0.18674698795180725f, 7,
+                            0.18692449355432778f, 8, 0.1946778711484594f, 9, 0.18604651162790695f},
+                    new float[]{0, 1f, 1, 1f, 2, 1f, 3, 1f, 4, 1f, 5, 1f, 6, 1f, 7, 1f, 8, 1f, 9,
+                            1f},
+                    new float[]{0, 0.14901960784313725f, 1, 0.2f, 2, 0.24901960784313726f, 3,
+                            0.30392156862745096f, 4, 0.3784313725490196f, 5, 0.4235294117647059f, 6,
+                            0.48823529411764705f, 7, 0.6450980392156863f, 8, 0.7666666666666666f, 9,
+                            0.8313725490196078f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.10619469026548674f, 1, 0.11924686192468618f, 2,
+                            0.13046448087431692f, 3, 0.14248366013071895f, 4, 0.1506024096385542f,
+                            5, 0.16220238095238093f, 6, 0.16666666666666666f, 7,
+                            0.16666666666666666f, 8, 0.162280701754386f, 9, 0.15686274509803924f},
+                    new float[]{0, 1f, 1, 1f, 2, 1f, 3, 1f, 4, 1f, 5, 1f, 6, 1f, 7, 1f, 8, 1f, 9,
+                            1f},
+                    new float[]{0, 0.44313725490196076f, 1, 0.46862745098039216f, 2,
+                            0.47843137254901963f, 3, 0.5f, 4, 0.5117647058823529f, 5,
+                            0.5607843137254902f, 6, 0.6509803921568628f, 7, 0.7509803921568627f, 8,
+                            0.8509803921568627f, 9, 0.9f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.03561253561253561f, 1, 0.05098039215686275f, 2,
+                            0.07516339869281045f, 3, 0.09477124183006536f, 4, 0.1150326797385621f,
+                            5, 0.134640522875817f, 6, 0.14640522875816991f, 7, 0.1582397003745319f,
+                            8, 0.15773809523809523f, 9, 0.15359477124183002f},
+                    new float[]{0, 1f, 1, 1f, 2, 1f, 3, 1f, 4, 1f, 5, 1f, 6, 1f, 7, 1f, 8, 1f, 9,
+                            1f},
+                    new float[]{0, 0.4588235294117647f, 1, 0.5f, 2, 0.5f, 3, 0.5f, 4, 0.5f, 5, 0.5f,
+                            6, 0.5f, 7, 0.6509803921568628f, 8, 0.7803921568627451f, 9, 0.9f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.9596491228070175f, 1, 0.9593837535014005f, 2,
+                            0.9514767932489452f, 3, 0.943859649122807f, 4, 0.9396825396825397f, 5,
+                            0.9395424836601307f, 6, 0.9393939393939394f, 7, 0.9362745098039216f, 8,
+                            0.9754098360655739f, 9, 0.9824561403508771f},
+                    new float[]{0, 0.84070796460177f, 1, 0.8206896551724138f, 2,
+                            0.7979797979797981f, 3, 0.7661290322580644f, 4, 0.9051724137931036f, 5,
+                            1f, 6, 1f, 7, 1f, 8, 1f, 9, 1f},
+                    new float[]{0, 0.22156862745098038f, 1, 0.2843137254901961f, 2,
+                            0.388235294117647f, 3, 0.48627450980392156f, 4, 0.5450980392156863f, 5,
+                            0.6f, 6, 0.6764705882352942f, 7, 0.8f, 8, 0.8803921568627451f, 9,
+                            0.9254901960784314f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.841025641025641f, 1, 0.8333333333333334f, 2,
+                            0.8285256410256411f, 3, 0.821522309711286f, 4, 0.8083333333333333f, 5,
+                            0.8046594982078853f, 6, 0.8005822416302766f, 7, 0.7842377260981912f, 8,
+                            0.7771084337349398f, 9, 0.7747747747747749f},
+                    new float[]{0, 1f, 1, 1f, 2, 1f, 3, 1f, 4, 1f, 5, 1f, 6, 1f, 7,
+                            0.737142857142857f, 8, 0.6434108527131781f, 9, 0.46835443037974644f},
+                    new float[]{0, 0.12745098039215685f, 1, 0.15490196078431373f, 2,
+                            0.20392156862745098f, 3, 0.24901960784313726f, 4, 0.3137254901960784f,
+                            5, 0.36470588235294116f, 6, 0.44901960784313727f, 7,
+                            0.6568627450980392f, 8, 0.7470588235294118f, 9, 0.8450980392156863f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0f, 1, 0f, 2, 0f, 3, 0f, 4, 0f, 5, 0f, 6, 0f, 7, 0f, 8, 0f, 9,
+                            0f},
+                    new float[]{0, 0f, 1, 0f, 2, 0f, 3, 0f, 4, 0f, 5, 0f, 6, 0f, 7, 0f, 8, 0f, 9,
+                            0f},
+                    new float[]{0, 0.14901960784313725f, 1, 0.2f, 2, 0.2980392156862745f, 3, 0.4f,
+                            4, 0.4980392156862745f, 5, 0.6196078431372549f, 6, 0.7176470588235294f,
+                            7, 0.8196078431372549f, 8, 0.9176470588235294f, 9, 0.9490196078431372f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.955952380952381f, 1, 0.9681069958847737f, 2,
+                            0.9760479041916167f, 3, 0.9873563218390804f, 4, 0f, 5, 0f, 6,
+                            0.009057971014492771f, 7, 0.026748971193415648f, 8,
+                            0.041666666666666616f, 9, 0.05303030303030304f},
+                    new float[]{0, 1f, 1, 0.8350515463917526f, 2, 0.6929460580912863f, 3,
+                            0.6387665198237885f, 4, 0.6914893617021276f, 5, 0.7583892617449666f, 6,
+                            0.8070175438596495f, 7, 0.9310344827586209f, 8, 1f, 9, 1f},
+                    new float[]{0, 0.27450980392156865f, 1, 0.3803921568627451f, 2,
+                            0.4725490196078432f, 3, 0.5549019607843138f, 4, 0.6313725490196078f, 5,
+                            0.707843137254902f, 6, 0.7764705882352941f, 7, 0.8294117647058823f, 8,
+                            0.9058823529411765f, 9, 0.9568627450980391f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.7514619883040936f, 1, 0.7679738562091503f, 2,
+                            0.7802083333333333f, 3, 0.7844311377245509f, 4, 0.796875f, 5,
+                            0.8165618448637316f, 6, 0.8487179487179487f, 7, 0.8582375478927203f, 8,
+                            0.8562091503267975f, 9, 0.8666666666666667f},
+                    new float[]{0, 1f, 1, 1f, 2, 0.8163265306122449f, 3, 0.6653386454183268f, 4,
+                            0.7547169811320753f, 5, 0.929824561403509f, 6, 0.9558823529411766f, 7,
+                            0.9560439560439562f, 8, 1f, 9, 1f},
+                    new float[]{0, 0.2235294117647059f, 1, 0.3f, 2, 0.38431372549019605f, 3,
+                            0.492156862745098f, 4, 0.5843137254901961f, 5, 0.6647058823529411f, 6,
+                            0.7333333333333334f, 7, 0.8215686274509804f, 8, 0.9f, 9,
+                            0.9411764705882353f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.6666666666666666f, 1, 0.6666666666666666f, 2,
+                            0.6666666666666666f, 3, 0.6666666666666666f, 4, 0.6666666666666666f, 5,
+                            0.6666666666666666f, 6, 0.6666666666666666f, 7, 0.6666666666666666f, 8,
+                            0.6666666666666666f, 9, 0.6666666666666666f},
+                    new float[]{0, 0.24590163934426232f, 1, 0.17880794701986752f, 2,
+                            0.14606741573033713f, 3, 0.13761467889908252f, 4, 0.14893617021276592f,
+                            5, 0.16756756756756758f, 6, 0.20312500000000017f, 7,
+                            0.26086956521739135f, 8, 0.29999999999999966f, 9, 0.5000000000000004f},
+                    new float[]{0, 0.2392156862745098f, 1, 0.296078431372549f, 2,
+                            0.34901960784313724f, 3, 0.4274509803921569f, 4, 0.5392156862745098f, 5,
+                            0.6372549019607843f, 6, 0.7490196078431373f, 7, 0.8196078431372549f, 8,
+                            0.8823529411764706f, 9, 0.9372549019607843f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.9678571428571429f, 1, 0.9944812362030905f, 2, 0f, 3, 0f, 4,
+                            0.0047348484848484815f, 5, 0.00316455696202532f, 6, 0f, 7,
+                            0.9980392156862745f, 8, 0.9814814814814816f, 9, 0.9722222222222221f},
+                    new float[]{0, 1f, 1, 0.7023255813953488f, 2, 0.6638655462184874f, 3,
+                            0.6521739130434782f, 4, 0.7719298245614035f, 5, 0.8315789473684211f, 6,
+                            0.6867469879518071f, 7, 0.7264957264957265f, 8, 0.8181818181818182f, 9,
+                            0.8181818181818189f},
+                    new float[]{0, 0.27450980392156865f, 1, 0.4215686274509804f, 2,
+                            0.4666666666666667f, 3, 0.503921568627451f, 4, 0.5529411764705883f, 5,
+                            0.6274509803921569f, 6, 0.6745098039215687f, 7, 0.7705882352941176f, 8,
+                            0.892156862745098f, 9, 0.9568627450980391f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.9052287581699346f, 1, 0.9112021857923498f, 2,
+                            0.9270152505446624f, 3, 0.9343137254901961f, 4, 0.9391534391534391f, 5,
+                            0.9437984496124031f, 6, 0.943661971830986f, 7, 0.9438943894389439f, 8,
+                            0.9426229508196722f, 9, 0.9444444444444444f},
+                    new float[]{0, 1f, 1, 0.8133333333333332f, 2, 0.7927461139896375f, 3,
+                            0.7798165137614679f, 4, 0.7777777777777779f, 5, 0.8190476190476191f, 6,
+                            0.8255813953488372f, 7, 0.8211382113821142f, 8, 0.8133333333333336f, 9,
+                            0.8000000000000006f},
+                    new float[]{0, 0.2f, 1, 0.29411764705882354f, 2, 0.3784313725490196f, 3,
+                            0.42745098039215684f, 4, 0.4764705882352941f, 5, 0.5882352941176471f, 6,
+                            0.6627450980392157f, 7, 0.7588235294117647f, 8, 0.8529411764705882f, 9,
+                            0.9411764705882353f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.6884057971014492f, 1, 0.6974789915966387f, 2,
+                            0.7079889807162534f, 3, 0.7154471544715447f, 4, 0.7217741935483872f, 5,
+                            0.7274143302180687f, 6, 0.7272727272727273f, 7, 0.7258064516129031f, 8,
+                            0.7252252252252251f, 9, 0.7333333333333333f},
+                    new float[]{0, 0.8214285714285715f, 1, 0.6878612716763006f, 2,
+                            0.6080402010050251f, 3, 0.5774647887323943f, 4, 0.5391304347826086f, 5,
+                            0.46724890829694316f, 6, 0.4680851063829788f, 7, 0.462686567164179f, 8,
+                            0.45679012345678977f, 9, 0.4545454545454551f},
+                    new float[]{0, 0.2196078431372549f, 1, 0.33921568627450976f, 2,
+                            0.39019607843137255f, 3, 0.4176470588235294f, 4, 0.45098039215686275f,
+                            5, 0.5509803921568628f, 6, 0.6313725490196078f, 7, 0.7372549019607844f,
+                            8, 0.8411764705882353f, 9, 0.9352941176470588f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.6470588235294118f, 1, 0.6516666666666667f, 2,
+                            0.6464174454828661f, 3, 0.6441441441441442f, 4, 0.6432748538011696f, 5,
+                            0.6416666666666667f, 6, 0.6402439024390243f, 7, 0.6412429378531074f, 8,
+                            0.6435185185185186f, 9, 0.6428571428571429f},
+                    new float[]{0, 0.8095238095238095f, 1, 0.6578947368421053f, 2,
+                            0.5721925133689839f, 3, 0.5362318840579711f, 4, 0.5f, 5,
+                            0.4424778761061947f, 6, 0.44086021505376327f, 7, 0.44360902255639095f,
+                            8, 0.4499999999999997f, 9, 0.4375000000000006f},
+                    new float[]{0, 0.16470588235294117f, 1, 0.2980392156862745f, 2,
+                            0.36666666666666664f, 3, 0.40588235294117647f, 4, 0.44705882352941173f,
+                            5, 0.5568627450980392f, 6, 0.6352941176470588f, 7, 0.7392156862745098f,
+                            8, 0.8431372549019608f, 9, 0.9372549019607843f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.46732026143790845f, 1, 0.4718614718614719f, 2,
+                            0.4793650793650794f, 3, 0.48071625344352614f, 4, 0.4829683698296837f, 5,
+                            0.484375f, 6, 0.4841269841269842f, 7, 0.48444444444444457f, 8,
+                            0.48518518518518516f, 9, 0.4907407407407408f},
+                    new float[]{0, 1f, 1, 1f, 2, 1f, 3, 1f, 4, 1f, 5, 0.6274509803921569f, 6,
+                            0.41832669322709176f, 7, 0.41899441340782106f, 8, 0.4128440366972478f,
+                            9, 0.4090909090909088f},
+                    new float[]{0, 0.1f, 1, 0.15098039215686274f, 2, 0.20588235294117646f, 3,
+                            0.2372549019607843f, 4, 0.26862745098039215f, 5, 0.4f, 6,
+                            0.5078431372549019f, 7, 0.6490196078431372f, 8, 0.7862745098039216f, 9,
+                            0.9137254901960784f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.5444444444444444f, 1, 0.5555555555555556f, 2,
+                            0.5555555555555556f, 3, 0.553763440860215f, 4, 0.5526315789473684f, 5,
+                            0.5555555555555556f, 6, 0.5555555555555555f, 7, 0.5555555555555556f, 8,
+                            0.5512820512820514f, 9, 0.5666666666666667f},
+                    new float[]{0, 0.24590163934426232f, 1, 0.19148936170212766f, 2,
+                            0.1791044776119403f, 3, 0.18343195266272191f, 4, 0.18446601941747576f,
+                            5, 0.1538461538461539f, 6, 0.15625000000000003f, 7,
+                            0.15328467153284678f, 8, 0.15662650602409653f, 9, 0.151515151515151f},
+                    new float[]{0, 0.1196078431372549f, 1, 0.1843137254901961f, 2,
+                            0.2627450980392157f, 3, 0.33137254901960783f, 4, 0.403921568627451f, 5,
+                            0.5411764705882354f, 6, 0.6235294117647059f, 7, 0.7313725490196079f, 8,
+                            0.8372549019607843f, 9, 0.9352941176470588f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.022222222222222223f, 1, 0.02469135802469136f, 2,
+                            0.031249999999999997f, 3, 0.03947368421052631f, 4, 0.04166666666666668f,
+                            5, 0.043650793650793655f, 6, 0.04411764705882352f, 7,
+                            0.04166666666666652f, 8, 0.04444444444444459f, 9, 0.05555555555555529f},
+                    new float[]{0, 0.33333333333333337f, 1, 0.2783505154639175f, 2,
+                            0.2580645161290323f, 3, 0.25675675675675674f, 4, 0.2528735632183908f, 5,
+                            0.17500000000000002f, 6, 0.15315315315315312f, 7, 0.15189873417721522f,
+                            8, 0.15789473684210534f, 9, 0.15789473684210542f},
+                    new float[]{0, 0.08823529411764705f, 1, 0.19019607843137254f, 2,
+                            0.2431372549019608f, 3, 0.2901960784313725f, 4, 0.3411764705882353f, 5,
+                            0.47058823529411764f, 6, 0.5647058823529412f, 7, 0.6901960784313725f, 8,
+                            0.8137254901960784f, 9, 0.9254901960784314f}
+            ),
+            new TonalPalette(
+                    new float[]{0, 0.050884955752212385f, 1, 0.07254901960784313f, 2,
+                            0.0934640522875817f, 3, 0.10457516339869281f, 4, 0.11699346405228758f,
+                            5, 0.1255813953488372f, 6, 0.1268939393939394f, 7, 0.12533333333333332f,
+                            8, 0.12500000000000003f, 9, 0.12777777777777777f},
+                    new float[]{0, 1f, 1, 1f, 2, 1f, 3, 1f, 4, 1f, 5, 1f, 6, 1f, 7, 1f, 8, 1f, 9,
+                            1f},
+                    new float[]{0, 0.44313725490196076f, 1, 0.5f, 2, 0.5f, 3, 0.5f, 4, 0.5f, 5,
+                            0.5784313725490196f, 6, 0.6549019607843137f, 7, 0.7549019607843137f, 8,
+                            0.8509803921568627f, 9, 0.9411764705882353f}
             )
     };
 }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 9ef05c5..7e7890d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -112,6 +112,7 @@
         public boolean dualTarget = false;
         public boolean isTransient = false;
         public String expandedAccessibilityClassName;
+        public SlashState slash;
 
         public boolean copyTo(State other) {
             if (other == null) throw new IllegalArgumentException();
@@ -126,7 +127,8 @@
                     || !Objects.equals(other.disabledByPolicy, disabledByPolicy)
                     || !Objects.equals(other.state, state)
                     || !Objects.equals(other.isTransient, isTransient)
-                    || !Objects.equals(other.dualTarget, dualTarget);
+                    || !Objects.equals(other.dualTarget, dualTarget)
+                    || !Objects.equals(other.slash, slash);
             other.icon = icon;
             other.label = label;
             other.contentDescription = contentDescription;
@@ -136,6 +138,7 @@
             other.state = state;
             other.dualTarget = dualTarget;
             other.isTransient = isTransient;
+            other.slash = slash != null ? slash.copy() : null;
             return changed;
         }
 
@@ -155,6 +158,7 @@
             sb.append(",dualTarget=").append(dualTarget);
             sb.append(",isTransient=").append(isTransient);
             sb.append(",state=").append(state);
+            sb.append(",slash=\"").append(slash).append("\"");
             return sb.append(']');
         }
 
@@ -246,4 +250,34 @@
         }
     }
 
+    @ProvidesInterface(version = SlashState.VERSION)
+    public static class SlashState {
+        public static final int VERSION = 2;
+
+        public boolean isSlashed;
+        public float rotation;
+
+        @Override
+        public String toString() {
+            return "isSlashed=" + isSlashed + ",rotation=" + rotation;
+        }
+
+        @Override
+        public boolean equals(Object o) {
+            if (o == null) return false;
+            try {
+                return (((SlashState) o).rotation == rotation)
+                        && (((SlashState) o).isSlashed == isSlashed);
+            } catch (ClassCastException e) {
+                return false;
+            }
+        }
+
+        public SlashState copy() {
+            SlashState state = new SlashState();
+            state.rotation = rotation;
+            state.isSlashed = isSlashed;
+            return state;
+        }
+    }
 }
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index ee51f8d..137926e 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -36,7 +36,7 @@
     <string name="keyguard_low_battery" msgid="9218432555787624490">"Зарядтағышты қосыңыз."</string>
     <string name="keyguard_instructions_when_pattern_disabled" msgid="8566679946700751371">"Ашу үшін \"Мәзір\" пернесін басыңыз."</string>
     <string name="keyguard_network_locked_message" msgid="6743537524631420759">"Желі құлыптаулы"</string>
-    <string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"SIM картасы енгізілмеген"</string>
+    <string name="keyguard_missing_sim_message_short" msgid="6327533369959764518">"SIM картасы салынбаған"</string>
     <string name="keyguard_missing_sim_message" product="tablet" msgid="4550152848200783542">"Планшетте SIM картасы жоқ."</string>
     <string name="keyguard_missing_sim_message" product="default" msgid="6585414237800161146">"Телефонда SIM картасы жоқ."</string>
     <string name="keyguard_missing_sim_instructions" msgid="7350295932015220392">"SIM картасын енгізіңіз."</string>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
index 70e4780..30c10dc 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_disabled.xml
@@ -14,16 +14,14 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32.0dp"
-        android:height="29.5dp"
-        android:viewportWidth="26.0"
-        android:viewportHeight="24.0">
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M17.500000,16.500000L5.800000,3.400000c0.000000,0.000000 0.000000,0.000000 0.000000,0.000000l-2.700000,-3.000000L1.600000,1.800000l2.200000,2.500000c-2.000000,1.000000 -3.200000,2.000000 -3.400000,2.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l3.200000,-3.900000l2.400000,2.700000l1.500000,-1.400000L17.500000,16.500000L17.500000,16.500000z"
-        android:fillAlpha=".3"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000c-1.900000,0.000000 -3.600000,0.300000 -5.200000,0.700000L18.700001,15.000000L25.600000,6.500000z"
-        android:fillAlpha=".3"/>
+    android:width="32.0dp"
+    android:height="29.5dp"
+    android:viewportWidth="26.0"
+    android:viewportHeight="24.0">
+    <group
+        android:translateY="2">
+        <path
+            android:fillColor="#FFFFFFFF"
+            android:pathData="M13.000000,22.000000L25.600000,6.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+    </group>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane_disable.xml b/packages/SystemUI/res/drawable/ic_signal_airplane_disable.xml
index 09a67e1..c4ac7ffb 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane_disable.xml
+++ b/packages/SystemUI/res/drawable/ic_signal_airplane_disable.xml
@@ -45,7 +45,7 @@
             <group
                 android:name="plane"
                 android:translateX="23.481"
-                android:translateY="18.71151" >
+                android:translateY="15.71151" >
                 <path
                     android:name="plane_1"
                     android:pathData="M 18.9439849854,7.98849487305 c 0.0,0.0 0.0,-4.0 0.0,-4.0 c 0.0,0.0 -16.0,-10.0 -16.0,-10.0 c 0.0,0.0 0.0,-11.0 0.0,-11.0 c 0.0,-1.70001220703 -1.30000305176,-3.0 -3.0,-3.0 c -1.69999694824,0.0 -3.0,1.29998779297 -3.0,3.0 c 0.0,0.0 0.0,11.0 0.0,11.0 c 0.0,0.0 -16.0,10.0 -16.0,10.0 c 0.0,0.0 0.0,4.0 0.0,4.0 c 0.0,0.0 16.0,-5.0 16.0,-5.0 c 0.0,0.0 0.0,11.0 0.0,11.0 c 0.0,0.0 -4.0,3.0 -4.0,3.0 c 0.0,0.0 0.0,3.0 0.0,3.0 c 0.0,0.0 7.0,-2.0 7.0,-2.0 c 0.0,0.0 7.0,2.0 7.0,2.0 c 0.0,0.0 0.0,-3.0 0.0,-3.0 c 0.0,0.0 -4.0,-3.0 -4.0,-3.0 c 0.0,0.0 0.0,-11.0 0.0,-11.0 c 0.0,0.0 16.0,5.0 16.0,5.0 Z"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 718142f..aa1525d 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Tot <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Hou"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Vervang"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Programme wat op die agtergrond loop"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tik vir besonderhede oor battery- en datagebruik"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 91e6b2e..afef464 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"እርስዎ ኢሜይሎችን፣ መተግበሪያዎችን እና ድር ጣቢያዎችንም ጨምሮ የግል የአውታረ መረብ እንቅስቃሴዎን ከሚከታተለው ከ<xliff:g id="APPLICATION">%1$s</xliff:g> ጋር ተገናኝተዋል።"</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"የእርስዎ የሥራ መገለጫ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> የሚተዳደር ነው። መገለጫው ኢሜይሎችን፣ መተግበሪያዎችን፣ እና የድር ጣቢያዎችን ጨምሮ የአውታረ መረብ እንቅስቃሴን መቆጣጠር ከሚችለው ከ<xliff:g id="APPLICATION">%2$s</xliff:g> ጋር ተገናኝቷል።\n\nለተጨማሪ መረጃ የእርስዎን አስተዳዳሪ ያነጋግሩ።"</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"የእርስዎ የሥራ መገለጫ በ<xliff:g id="ORGANIZATION">%1$s</xliff:g> የሚተዳደር ነው። መገለጫው ኢሜይሎችን፣ መተግበሪያዎችን፣ እና የድር ጣቢያዎችን ጨምሮ የአውታረ መረብ እንቅስቃሴን መቆጣጠር ከሚችለው ከ<xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ጋር ተገናኝቷል።\n\nበተጨማሪ የእርስዎን የግል የአውታረ መረብ እንቅስቃሴ መቆጣጠር ከሚችለው ከ<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ጋር ተገናኝተዋል።"</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"ለ<xliff:g id="USER_NAME">%1$s</xliff:g> ተከፍቷል"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"እራስዎ እስኪከፍቱት ድረስ መሣሪያ እንደተቆለፈ ይቆያል"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"ማሳወቂያዎችን ፈጥነው ያግኙ"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"ከመክፈትዎ በፊት ይመልከቷቸው"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"እስከ <xliff:g id="ID_1">%s</xliff:g> ድረስ"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"አቆይ"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"ተካ"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"በጀርባ ውስጥ የሚያሄዱ መተግበሪያዎች"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"በባትሪ እና ውሂብ አጠቃቀም ላይ ዝርዝሮችን ለማግኘት መታ ያድርጉ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index c04d0db..76854f1 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -778,8 +778,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"حتى <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"الإبقاء على الإعدادات"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"استبدال"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"التطبيقات التي تعمل في الخلفية"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"انقر للحصول على تفاصيل حول البطارية واستخدام البيانات"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 4b9971b..b0f813f 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> vaxtına qədər"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Saxlayın"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Əvəz edin"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Arxa fonda işləyən tətbiqlər"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Batareya və data istifadəsi haqqında ətraflı məlumat üçün klikləyin"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 0065ffe..4f508e8 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -400,7 +400,7 @@
     <string name="user_logout_notification_text" msgid="3350262809611876284">"Odjavite aktuelnog korisnika"</string>
     <string name="user_logout_notification_action" msgid="1195428991423425062">"ODJAVI KORISNIKA"</string>
     <string name="user_add_user_title" msgid="4553596395824132638">"Dodajete novog korisnika?"</string>
-    <string name="user_add_user_message_short" msgid="2161624834066214559">"Kada dodate novog korisnika, ta osoba treba da podesi sopstveni prostor.\n\nSvaki korisnik može da ažurira aplikacije za sve ostale korisnike."</string>
+    <string name="user_add_user_message_short" msgid="2161624834066214559">"Kada dodate novog korisnika, ta osoba treba da podesi svoj prostor.\n\nSvaki korisnik može da ažurira aplikacije za sve ostale korisnike."</string>
     <string name="user_remove_user_title" msgid="4681256956076895559">"Želite li da uklonite korisnika?"</string>
     <string name="user_remove_user_message" msgid="1453218013959498039">"Sve aplikacije i podaci ovog korisnika će biti izbrisani."</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"Ukloni"</string>
@@ -468,8 +468,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste sa aplikacijom <xliff:g id="APPLICATION">%1$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži, uključujući imejlove, aplikacije i veb-sajtove."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nViše informacija potražite od administratora."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Profilom za Work upravlja <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Povezan je sa aplikacijom <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, koja može da nadgleda aktivnosti na poslovnoj mreži, uključujući imejlove, aplikacije i veb-sajtove.\n\nPovezani ste i sa aplikacijom <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, koja može da nadgleda aktivnosti na ličnoj mreži."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Otključano za korisnika <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Uređaj će ostati zaključan dok ga ne otključate ručno"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Brže dobijajte obaveštenja"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Pregledajte ih pre otključavanja"</string>
@@ -592,8 +591,8 @@
     <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Taster sa strelicom nalevo"</string>
     <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Taster sa strelicom nadesno"</string>
     <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Taster sa centralnom strelicom"</string>
-    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tabulator"</string>
-    <string name="keyboard_key_space" msgid="2499861316311153293">"Taster za razmak"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Razmak"</string>
     <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
     <string name="keyboard_key_backspace" msgid="1559580097512385854">"Taster za brisanje unazad"</string>
     <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Taster za reprodukciju/pauziranje"</string>
@@ -659,7 +658,7 @@
   </string-array>
     <string name="menu_ime" msgid="4998010205321292416">"Prebacivač za tastaturu"</string>
     <string name="save" msgid="2311877285724540644">"Sačuvaj"</string>
-    <string name="reset" msgid="2448168080964209908">"Ponovo postavi"</string>
+    <string name="reset" msgid="2448168080964209908">"Resetuj"</string>
     <string name="adjust_button_width" msgid="6138616087197632947">"Prilagodi širinu dugmeta"</string>
     <string name="clipboard" msgid="1313879395099896312">"Privremena memorija"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"Prilagođeno dugme za navigaciju"</string>
@@ -767,8 +766,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Do <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Zadrži"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Zameni"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikacije pokrenute u pozadini"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Dodirnite da biste pregledali detalje o bateriji i potrošnji podataka"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 313285be..58bb004 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -772,8 +772,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Да <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Пакінуць"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Замяніць"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Праграмы, якія працуюць у фонавым рэжыме"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Дакраніцеся, каб атрымаць падрабязныя звесткі пра выкарыстанне трафіка і акумулятара"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 5934bd2..f649338 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"До <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Запазване"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Замяна"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Приложения, работещи на заден план"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Докоснете за подробности относно използването на батерията и преноса на данни"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 181c0871..8180453 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"আপনি <xliff:g id="APPLICATION">%1$s</xliff:g> এর সাথে সংযুক্ত হয়েছেন, যা ইমেল, অ্যাপ এবং ওয়েবসাইটগুলি সহ আপনার ব্যক্তিগত নেটওয়ার্কের কার্যকলাপ নিরীক্ষণ করবে৷"</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কর্মস্থলের প্রোফাইল পরিচালনা করে। প্রোফাইলটি <xliff:g id="APPLICATION">%2$s</xliff:g> এর সাথে সংযুক্ত, যেটি ইমেল, অ্যাপ, ও ওয়েবসাইট সহ আপনার কর্মস্থলের নেটওয়ার্ক কার্যকলাপের উপরে নজর রাখতে পারে।\n\nআরো তথ্যের জন্য প্রশাসকের সাথে যোগাযোগ করুন।"</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> আপনার কর্মস্থলের প্রোফাইল পরিচালনা করে। প্রোফাইলটি <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> এর সাথে সংযুক্ত, যেটি ইমেল অ্যাপ, ও ওয়েবসাইট সহ আপনার কর্মস্থলের নেটওয়ার্ক কার্যকলাপের উপরে নজর রাখতে পারে।\n\n এ ছাড়াও আপনি <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> এর সাথে সংযুক্ত, যেটি আপনার ব্যক্তিগত নেটওয়ার্কে নজর রাখে।"</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g> এর জন্য আনলক করা হয়েছে"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"আপনি নিজে আনলক না করা পর্যন্ত ডিভাইসটি লক হয়ে থাকবে"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"বিজ্ঞপ্তিগুলি আরো দ্রুত পান"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"আপনি আনলক করার আগে ওগুলো দেখুন"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> পর্যন্ত"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"রাখুন"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"বদলে দিন"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"পটভূমিতে অ্যাপ চালু আছে"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"ব্যাটারি এবং ডেটার ব্যবহারের বিশদ বিবরণের জন্য ট্যাপ করুন"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index a06da7c..a0e0a25 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -650,7 +650,7 @@
     <item msgid="1545641631806817203">"Međumemorija"</item>
     <item msgid="5742013440802239414">"Kôd tipke"</item>
     <item msgid="8802889973626281575">"Prebacivač tastatura"</item>
-    <item msgid="8175437057325747277">"Nema"</item>
+    <item msgid="8175437057325747277">"Ništa"</item>
   </string-array>
   <string-array name="nav_bar_layouts">
     <item msgid="8077901629964902399">"Normalna"</item>
@@ -660,7 +660,7 @@
   </string-array>
     <string name="menu_ime" msgid="4998010205321292416">"Prebacivač tastatura"</string>
     <string name="save" msgid="2311877285724540644">"Sačuvaj"</string>
-    <string name="reset" msgid="2448168080964209908">"Vrati na zadano"</string>
+    <string name="reset" msgid="2448168080964209908">"Vraćanje na zadano"</string>
     <string name="adjust_button_width" msgid="6138616087197632947">"Podesite širinu dugmeta"</string>
     <string name="clipboard" msgid="1313879395099896312">"Međumemorija"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"Prilagođeno dugme za navigaciju"</string>
@@ -768,8 +768,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Do <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Zadrži"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Zamijeni"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikacije koje rade u pozadini"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Dodirnite za detalje o bateriji i prijenosu podataka"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index bd5e6cc..9457cf6 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Fins a les <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Conserva"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Substitueix"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplicacions que s\'estan executant en segon pla"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Toca per obtenir informació sobre l\'ús de dades i la bateria"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index e3af288..83138b4 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -772,8 +772,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Do <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Zachovat"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Nahradit"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikace běžící na pozadí"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Klepnutím zobrazíte podrobnosti o využití baterie a dat"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index fefbff7..7a66789 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Indtil <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Behold"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Erstat"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apps, der kører i baggrunden"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tryk for at se oplysninger om batteri- og dataforbrug"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 714341d..5130e5b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -489,7 +489,7 @@
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Du verwendest dein Arbeitsprofil."</string>
     <string name="stream_voice_call" msgid="4410002696470423714">"Anruf"</string>
     <string name="stream_system" msgid="7493299064422163147">"System"</string>
-    <string name="stream_ring" msgid="8213049469184048338">"Klingeln lassen"</string>
+    <string name="stream_ring" msgid="8213049469184048338">"Klingelton"</string>
     <string name="stream_music" msgid="9086982948697544342">"Medien"</string>
     <string name="stream_alarm" msgid="5209444229227197703">"Wecker"</string>
     <string name="stream_notification" msgid="2563720670905665031">"Benachrichtigung"</string>
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Bis <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Beibehalten"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Ersetzen"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apps, die im Hintergrund ausgeführt werden"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Für weitere Informationen zur Akku- und Datennutzung tippen"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 8838b66..44e9653 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Έως τις <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Διατήρηση"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Αντικατάσταση"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Εφαρμογές που εκτελούνται στο παρασκήνιο"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Πατήστε για λεπτομέρειες σχετικά με τη χρήση μπαταρίας και δεδομένων"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 9542d75..056a1e0 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Until <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Keep"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Replace"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apps running in background"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tap for details on battery and data usage"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 9542d75..056a1e0 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Until <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Keep"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Replace"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apps running in background"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tap for details on battery and data usage"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 9542d75..056a1e0 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Until <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Keep"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Replace"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apps running in background"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tap for details on battery and data usage"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index d61d4de..3a69668 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Hasta la(s) <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Mantener"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Reemplazar"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apps que se ejecutan en segundo plano"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Presiona para obtener información sobre el uso de datos y de la batería"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index ea88456..894fcb0 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Hasta <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Conservar"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Reemplazar"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplicaciones que se están ejecutando en segundo plano"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Toca para ver información detallada sobre el uso de datos y la batería"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index b4f1022..c4a389ed 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Kuni ajani <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Säilita"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Asenda"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Rakendusi käitatakse taustal"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Aku ja andmekasutuse üksikasjade nägemiseks puudutage"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 214da9a..30ea6bf 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -354,7 +354,7 @@
     <string name="description_target_search" msgid="3091587249776033139">"Bilatu"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"Lerratu gora hau egiteko: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"Lerratu ezkerrera hau egiteko: <xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>."</string>
-    <string name="zen_priority_introduction" msgid="3070506961866919502">"Soinuek eta dardarek ez zaituzte eragotziko, zehazten dituzun alarmek, abisuek, gertaerek eta deitzaileek izan ezik."</string>
+    <string name="zen_priority_introduction" msgid="3070506961866919502">"Soinuek eta dardarek ez zaituzte oztoporik egingo, zehazten dituzun alarmek, abisuek, gertaerek eta deitzaileek izan ezik."</string>
     <string name="zen_priority_customize_button" msgid="7948043278226955063">"Pertsonalizatu"</string>
     <string name="zen_silence_introduction_voice" msgid="2284540992298200729">"Soinu eta dardara GUZTIAK blokeatuko dira, besteak beste, alarmak, musika, bideoak eta jokoak. Telefono-deiak egiteko aukera izaten jarraituko duzu."</string>
     <string name="zen_silence_introduction" msgid="3137882381093271568">"Soinu eta dardara GUZTIAK blokeatuko dira, besteak beste, alarmak, musika, bideoak eta jokoak."</string>
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> arte"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Utzi bere horretan"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Ordeztu"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikazioak exekutatzen ari dira atzeko planoan"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Sakatu bateriaren eta datuen erabilerari buruzko xehetasunak ikusteko"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 30782e4..63050ae 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"به <xliff:g id="APPLICATION">%1$s</xliff:g> وصل شده‌اید، که می‌تواند فعالیت شبکه شخصی شما را (ازجمله رایانامه‌‌ها، برنامه‌‌ها و وب‌سایت‌ها) کنترل کند."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"نمایه کاری شما توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این نمایه به <xliff:g id="APPLICATION">%2$s</xliff:g> متصل است که می‌تواند فعالیت شما در شبکه (ازجمله رایانامه‌ها، برنامه‌ها و وب‌سایت‌ها) را پایش کند.\n\nبرای اطلاعات بیشتر، با سرپرست سیستم تماس بگیرید."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"نمایه کاری‌تان توسط <xliff:g id="ORGANIZATION">%1$s</xliff:g> مدیریت می‌شود. این نمایه به <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> متصل است که می‌تواند تنظیمات، دسترسی شرکتی، برنامه‌ها، داده‌های مرتبط با دستگاه و اطلاعات مکان دستگاه شما را پایش کند.\n\nشما همچنین به <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> متصل هستید که می‌تواند فعالیت خصوصی شما را در شبکه پایش کند."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"قفل برای <xliff:g id="USER_NAME">%1$s</xliff:g> باز شد"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"دستگاه قفل باقی می‌ماند تا زمانی که قفل آن را به صورت دستی باز کنید"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"دریافت سریع‌تر اعلان‌ها"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"قبل از باز کردن قفل آنها را مشاهده کنید"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"تا <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"حفظ شود"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"جایگزین کردن"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"برنامه‌هایی که در پس‌زمینه اجرا می‌شوند"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"برای جزئیات مربوط به مصرف باتری و داده، ضربه بزنید"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index bbdfcdc..ec6a6d9 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> asti"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Säilytä"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Korvaa"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Sovelluksia käynnissä taustalla"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Katso lisätietoja akun ja datan käytöstä napauttamalla"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index a6f42c5..419e7f2 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Jusqu\'à <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Garder"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Remplacer"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Applications qui fonctionnent en arrière-plan"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Touchez ici pour afficher des détails sur l\'usage de la pile et des données"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index d00e98f..acca9a6 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -300,7 +300,7 @@
     <string name="quick_settings_wifi_off_label" msgid="7558778100843885864">"Wi-Fi désactivé"</string>
     <string name="quick_settings_wifi_on_label" msgid="7607810331387031235">"Wi-Fi activé"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="269990350383909226">"Aucun réseau Wi-Fi disponible"</string>
-    <string name="quick_settings_cast_title" msgid="7709016546426454729">"Diffuser"</string>
+    <string name="quick_settings_cast_title" msgid="7709016546426454729">"Caster"</string>
     <string name="quick_settings_casting" msgid="6601710681033353316">"Diffusion"</string>
     <string name="quick_settings_cast_device_default_name" msgid="5367253104742382945">"Appareil sans nom"</string>
     <string name="quick_settings_cast_device_default_description" msgid="2484573682378634413">"Prêt à caster"</string>
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Jusqu\'à <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Conserver"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Remplacer"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Applications en cours d\'exécution en arrière-plan"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Appuyer pour obtenir des informations sur l\'utilisation de la batterie et des données"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 416b359..3bc73d1 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Ata: <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Manter"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Substituír"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplicacións que se executan en segundo plano"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Toca para obter información sobre a batería e o uso de datos"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 857eaec..d0131e2 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"તમે <xliff:g id="APPLICATION">%1$s</xliff:g> સાથે કનેક્ટ થયાં છો, જે ઇમેઇલ્સ, ઍપ્લિકેશનો અને વેબસાઇટ્સ સહિત તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિને મૉનિટર કરી શકે છે."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા  સંચાલિત કરાય છે. આ પ્રોફાઇલ <xliff:g id="APPLICATION">%2$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે.\n\nવધુ માહિતી માટે, તમારા વ્યવસ્થાપકનો સંપર્ક કરો."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"તમારી કાર્ય પ્રોફાઇલ <xliff:g id="ORGANIZATION">%1$s</xliff:g> દ્વારા સંચાલિત થાય છે. આ પ્રોફાઇલ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> સાથે કનેક્ટ કરેલ છે, જે ઇમેઇલ, ઍપ્લિકેશનો અને વેબસાઇટો સહિતની તમારી નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે.\n\nતમે <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> સાથે પણ કનેક્ટ કરેલું છે, જે તમારી વ્યક્તિગત નેટવર્ક પ્રવૃત્તિનું નિયમન કરી શકે છે."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g> માટે અનલૉક કર્યુ"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"તમે ઉપકરણને મેન્યુઅલી અનલૉક કરશો નહીં ત્યાં સુધી તે લૉક રહેશે"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"વધુ ઝડપથી સૂચનાઓ મેળવો"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"તમે અનલૉક કરો તે પહેલાં તેમને જુઓ"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> સુધી"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"રાખો"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"બદલો"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"પૃષ્ઠભૂમિમાં ચાલી રહેલ ઍપ્લિકેશનો"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"બૅટરી અને ડેટા વપરાશ વિશેની વિગતો માટે ટૅપ કરો"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ad3bf6b..43e6001 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> तक"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"रखें"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"बदलें"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"ऐप्लिकेशन बैकग्राउंड में चल रहे हैं"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"बैटरी और डेटा उपयोग के विवरण पाने के लिए टैप करें"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index d7eab75..d99beae 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -766,8 +766,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Do <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Zadrži"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Zamijeni"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Izvođenje aplikacija u pozadini"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Dodirnite da biste vidjeli pojedinosti o potrošnji baterije i podataka"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 815dd12..a29dc24 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Eddig: <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Megtartás"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Csere"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"A háttérben még futnak alkalmazások"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Az akkumulátor töltöttségének és az adathasználat részleteinek megtekintéséhez koppintson"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index bc37813..2b0cba2 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Մինչև <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Պահել"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Փոխարինել"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Հետին ֆոնին գործարկվող հավելվածներ"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Հպել՝ մարտկոցի և տվյալների օգտագործման մասին մանրամասներ ստանալու համար"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index b73d10f..756acc6 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -67,14 +67,14 @@
     <string name="usb_debugging_secondary_user_message" msgid="8572228137833020196">"Pengguna yang saat ini masuk ke perangkat ini tidak dapat mengaktifkan debug USB. Untuk menggunakan fitur ini, beralih ke pengguna Admin."</string>
     <string name="compat_mode_on" msgid="6623839244840638213">"Perbesar utk mengisi layar"</string>
     <string name="compat_mode_off" msgid="4434467572461327898">"Rentangkn utk mngisi layar"</string>
-    <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Menyimpan tangkapan layar..."</string>
-    <string name="screenshot_saving_title" msgid="8242282144535555697">"Menyimpan tangkapan layar..."</string>
-    <string name="screenshot_saving_text" msgid="2419718443411738818">"Tangkapan layar sedang disimpan."</string>
-    <string name="screenshot_saved_title" msgid="6461865960961414961">"Tangkapan layar diambil."</string>
-    <string name="screenshot_saved_text" msgid="2685605830386712477">"Ketuk untuk melihat tangkapan layar."</string>
-    <string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat mengambil tangkapan layar."</string>
-    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Terjadi masalah saat menyimpan tangkapan layar."</string>
-    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Tidak dapat menyimpan tangkapan layar karena ruang penyimpanan terbatas."</string>
+    <string name="screenshot_saving_ticker" msgid="7403652894056693515">"Menyimpan screenshot..."</string>
+    <string name="screenshot_saving_title" msgid="8242282144535555697">"Menyimpan screenshot..."</string>
+    <string name="screenshot_saving_text" msgid="2419718443411738818">"Screenshot sedang disimpan."</string>
+    <string name="screenshot_saved_title" msgid="6461865960961414961">"Screenshot diambil."</string>
+    <string name="screenshot_saved_text" msgid="2685605830386712477">"Ketuk untuk melihat screenshot."</string>
+    <string name="screenshot_failed_title" msgid="705781116746922771">"Tidak dapat mengambil screenshot."</string>
+    <string name="screenshot_failed_to_save_unknown_text" msgid="7887826345701753830">"Terjadi masalah saat menyimpan screenshot."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Tidak dapat menyimpan screenshot karena ruang penyimpanan terbatas."</string>
     <string name="screenshot_failed_to_capture_text" msgid="173674476457581486">"Mengambil screenshot tidak diizinkan oleh aplikasi atau organisasi"</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Opsi transfer file USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Pasang sebagai pemutar media (MTP)"</string>
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Hingga <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Simpan"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Ganti"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikasi yang sedang berjalan di latar belakang"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tap untuk melihat detail baterai dan penggunaan data"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index eb9b620..0dd6d12 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Þú ert með tengingu við <xliff:g id="APPLICATION">%1$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Vinnusniðinu þínu er stýrt af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Sniðið er tengt <xliff:g id="APPLICATION">%2$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum\n\nFrekari upplýsingar fást hjá kerfisstjóra."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Vinnusniðinu þínu er stýrt af <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Sniðið er tengt <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, sem getur fylgst með netnotkun þinni, þ. á m. tölvupósti, forritum og vefsvæðum\n\nÞú ert einnig með tengingu við <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, sem getur fylgst með persónulegri netnotkun þinni."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Opnað fyrir <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Tækið verður læst þar til þú opnar það handvirkt"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Fáðu tilkynningar hraðar"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Sjáðu þær áður en þú opnar"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Þar til <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Halda"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Skipta út"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Forrit sem keyra í bakgrunni"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Ýttu til að fá upplýsingar um rafhlöðu- og gagnanotkun"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 402c027..6d53bd0 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Fino alle ore <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Mantieni"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Sostituisci"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"App in esecuzione in background"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tocca per conoscere i dettagli sull\'utilizzo dei dati e della batteria"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 6183774..8cac14d 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -770,8 +770,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"עד <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"שמור"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"החלף"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"אפליקציות שפועלות ברקע"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"הקש לקבלת פרטים על צריכה של נתונים וסוללה"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 5442c63..ea84748 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"終了時間: <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"設定を維持"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"設定を変更"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"バックグラウンドで実行中のアプリ"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"タップで電池やデータの使用量の詳細を確認"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 74e8441..ae50bd9 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g>-მდე"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"შენარჩუნება"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"ჩანაცვლება"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"ფონურ რეჟიმში გაშვებული აპები"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"შეეხეთ ბატარეისა და მონაცემების მოხმარების შესახებ დეტალური ინფორმაციისთვის"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 193eb5f..8b891bb 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> дейін"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Қалсын"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Ауыстыру"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Фонда жұмыс істеп тұрған қолданбалар"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Батарея мен деректер трафигі туралы мәліметтер алу үшін түртіңіз"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 8e671cf..3f7bd53 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"រហូត​ដល់ <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"រក្សានៅ​ដដែល"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"ជំនួស"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"កម្មវិធីដែលកំពុងដំណើរការនៅផ្ទៃខាងក្រោយ"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"ចុចដើម្បីទទួលបានព័ត៌មានលម្អិតអំពីការប្រើប្រាស់ថ្ម និងទិន្នន័យ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 1fe29b7..19fb3af 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> ತನಕ"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"ಇರಿಸಿ"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"ಬದಲಿಸಿ"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಹಿನ್ನೆಲೆಯಲ್ಲಿ ರನ್ ಆಗುತ್ತಿವೆ"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"ಬ್ಯಾಟರಿ ಮತ್ತು ಡೇಟಾ ಬಳಕೆಯ ವಿವರಗಳಿಗಾಗಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index d1e7fec..95dfeb4 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -468,8 +468,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g>에 연결되었습니다. 이 앱은 이메일, 앱, 웹사이트와 같은 내 개인 네트워크 활동을 모니터링할 수 있습니다."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 프로필이 <xliff:g id="APPLICATION">%2$s</xliff:g>에 연결되어 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n자세한 내용을 확인하려면 관리자에게 문의하세요."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"직장 프로필은 <xliff:g id="ORGANIZATION">%1$s</xliff:g>에서 관리합니다. 이 프로필은 <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>에 연결되어 이메일, 앱, 웹사이트와 같은 직장 네트워크 활동을 모니터링할 수 있습니다.\n\n개인 네트워크 활동을 모니터링할 수 있는 <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>에도 연결됩니다."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g>님 잠금 해제됨"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"수동으로 잠금 해제할 때까지 기기가 잠금 상태로 유지됩니다."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"알림을 더욱 빠르게 받기"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"잠금 해제하기 전에 알림을 봅니다."</string>
@@ -765,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g>까지"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"유지"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"바꾸기"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"백그라운드에서 실행 중인 앱"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"탭하여 배터리 및 데이터 사용량에 관한 세부정보 보기"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 04506e90..c8f0bc7 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -44,7 +44,7 @@
     <string name="battery_saver_start_action" msgid="5576697451677486320">"Батареянын кубатын үнөмдөгүчтү иштетүү"</string>
     <string name="status_bar_settings_settings_button" msgid="3023889916699270224">"Жөндөөлөр"</string>
     <string name="status_bar_settings_wifi_button" msgid="1733928151698311923">"Wi‑Fi"</string>
-    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Экранды авто-тегеретүү"</string>
+    <string name="status_bar_settings_auto_rotation" msgid="3790482541357798421">"Экрандын авто-айлануусу"</string>
     <string name="status_bar_settings_mute_label" msgid="554682549917429396">"ҮНСҮЗ"</string>
     <string name="status_bar_settings_auto_brightness_label" msgid="511453614962324674">"АВТО"</string>
     <string name="status_bar_settings_notifications" msgid="397146176280905137">"Эскертмелер"</string>
@@ -276,7 +276,7 @@
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="4910015762433302860">"Жупташкан түзмөктөр жок"</string>
     <string name="quick_settings_brightness_label" msgid="6968372297018755815">"Жарыктыгы"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="7305323031808150099">"Автоматтык бурулуу"</string>
-    <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Экранды авто-тегеретүү"</string>
+    <string name="accessibility_quick_settings_rotation" msgid="4231661040698488779">"Экрандын авто-айлануусу"</string>
     <string name="accessibility_quick_settings_rotation_value" msgid="8187398200140760213">"<xliff:g id="ID_1">%s</xliff:g> режими"</string>
     <string name="quick_settings_rotation_locked_label" msgid="6359205706154282377">"Буруу аракети кулпуланган"</string>
     <string name="quick_settings_rotation_locked_portrait_label" msgid="5102691921442135053">"Тигинен"</string>
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> чейин"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Ушундай калтыруу"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Алмаштыруу"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Фондо иштеп жаткан колдонмолор"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Батареянын кубаты жана Интернеттин колдонулушу жөнүндө билүү үчүн таптап коюңуз"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 767f98d..198e8f6 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"ຈົນຮອດ <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"ເກັບໄວ້"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"ແທນທີ່"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"ແອັບທີ່ກຳລັງເຮັດວຽກໃນພື້ນຫຼັງ"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"ແຕະເພື່ອເບິ່ງລາຍລະອຽດການນຳໃຊ້ແບັດເຕີຣີ ແລະ ອິນເຕີເນັດ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 7caaad4..d83737d 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -770,8 +770,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Iki <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Palikti"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Pakeisti"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Programos, veikiančios fone"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Palieskite ir sužinokite išsamios informacijos apie akumuliatoriaus bei duomenų naudojimą"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 3ada4ce..c997609 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -766,8 +766,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Līdz: <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Paturēt"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Aizstāt"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Lietotnes, kas darbojas fonā"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Pieskarieties, lai skatītu detalizētu informāciju par akumulatora un datu lietojumu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 92b76ea..56468a3 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"До <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Задржи"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Замени"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Апликациите се извршуваат во заднина"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Допрете за детали за батеријата и потрошениот сообраќај"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 17887b8..606b925 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"നിങ്ങൾ <xliff:g id="APPLICATION">%1$s</xliff:g> ആപ്പിലേക്ക് കണക്റ്റുചെയ്‌തിരിക്കുന്നു, ഇമെയിലുകൾ, ആപ്‌സ്, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാൻ ഈ ആപ്പിന് കഴിയും."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ മാനേജുചെയ്യുന്നത്. <xliff:g id="APPLICATION">%2$s</xliff:g> ആപ്പിലേക്ക് പ്രൊഫൈൽ കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്പുകൾ, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാനാകും.\n\nകൂടുതൽ വിവരങ്ങൾക്ക് നിങ്ങളുടെ അഡ്‌മിനെ ബന്ധപ്പെടുക."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"<xliff:g id="ORGANIZATION">%1$s</xliff:g> ആണ് നിങ്ങളുടെ ഔദ്യോഗിക പ്രൊഫൈൽ മാനേജുചെയ്യുന്നത്. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ആപ്പിലേക്ക് പ്രൊഫൈൽ കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് ഇമെയിലുകൾ, ആപ്പുകൾ, വെബ്‌സൈറ്റുകൾ എന്നിവ ഉൾപ്പെടെ നിങ്ങളുടെ ഔദ്യോഗിക നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാനാകും.\n\n<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ആപ്പിലേക്കും നിങ്ങൾ കണക്റ്റുചെയ്‌തിരിക്കുന്നു, അതിന് നിങ്ങളുടെ വ്യക്തിഗത നെറ്റ്‌വർക്ക് ആക്റ്റിവിറ്റി നിരീക്ഷിക്കാനാകും."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g> എന്നയാൾക്കായി അൺലോക്കുചെയ്‌തു"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"നിങ്ങൾ സ്വമേധയാ അൺലോക്കുചെയ്യുന്നതുവരെ ഉപകരണം ലോക്കുചെയ്‌തതായി തുടരും"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"അറിയിപ്പുകൾ വേഗത്തിൽ സ്വീകരിക്കുക"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"അൺലോക്കുചെയ്യുന്നതിന് മുമ്പ് അവ കാണുക"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> വരെ"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"സൂക്ഷിക്കുക"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"മാറ്റിസ്ഥാപിക്കുക"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"ആപ്പുകൾ പശ്ചാത്തലത്തിൽ റൺ ചെയ്യുന്നു"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"ബാറ്ററി, ഡാറ്റ ഉപയോഗം എന്നിവയുടെ വിശദാംശങ്ങളറിയാൻ ടാപ്പുചെയ്യുക"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 746b284..e1d9099 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> хүртэл"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Хадгалах"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Солих"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Цаана ажиллаж буй апп"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Батерей, дата ашиглалтын талаар дэлгэрэнгүй мэдээллийг харахын тулд товшино уу"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 1514b7c..634f8f7 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"आपण <xliff:g id="APPLICATION">%1$s</xliff:g> शी कनेक्‍ट केले आहे, जो ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकतो."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"आपले कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते. प्रोफाइल <xliff:g id="APPLICATION">%2$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकते.\n\nअधिक माहितीसाठी, आपल्या प्रशासकाशी संपर्क साधा."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"आपले कार्य प्रोफाइल <xliff:g id="ORGANIZATION">%1$s</xliff:g> द्वारे व्यवस्थापित केले जाते. प्रोफाइल <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> शी कनेक्‍ट केले आहे, जे ईमेल, अ‍ॅप्स आणि वेबसाइटसह आपल्‍या कार्य नेटवर्क क्रियाकलापाचे परीक्षण करू शकते.\n\nआपण <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> शीदेखील कनेक्‍ट केले आहे, जे आपल्या वैयक्तिक नेटवर्क क्रियाकलापाचे परीक्षण करू शकते."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g> साठी अनलॉक केले"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"आपण व्यक्तिचलितपणे अनलॉक करेपर्यंत डिव्हाइस लॉक केलेले राहील"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"सूचना अधिक जलद मिळवा"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"आपण अनलॉक करण्‍यापूर्वी त्यांना पहा"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> पर्यंत"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"ठेवा"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"पुनर्स्थित करा"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"अॅप्‍स बॅकग्राउंडमध्‍ये चालू आहेत"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"बॅटरी आणि डेटा वापराच्‍या तपशीलांसाठी टॅप करा"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 8d13d62..2fe3b4d 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Anda disambungkan ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda, termasuk e-mel, apl dan tapak web."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil itu dihubungkan ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nUntuk mendapatkan maklumat lanjut, hubungi pentadbir anda."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Profil kerja anda diurus oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil itu dihubungkan ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang boleh memantau aktiviti rangkaian kerja anda, termasuk e-mel, apl dan tapak web.\n\nAnda turut dihubungkan ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang boleh memantau aktiviti rangkaian peribadi anda."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Kunci dibuka untuk <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Peranti akan kekal terkunci sehingga anda membuka kunci secara manual"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Dapatkan pemberitahuan lebih cepat"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Lihat sebelum anda membuka kunci"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Hingga <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Simpan"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Gantikan"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apl yang berjalan di latar belakang"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Ketik untuk mendapatkan butiran tentang penggunaan kuasa bateri dan data"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 8079ecd..480293c 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> အထိ"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"သိမ်းထားရန်"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"အစားထိုးရန်"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"နောက်ခံတွင် ပွင့်နေသော အက်ပ်များ"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"ဘက်ထရီနှင့် ဒေတာအသုံးပြုမှု အသေးစိတ်ကို ကြည့်ရန် တို့ပါ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 7c86d1f..9715ac6 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Enheten er koblet til <xliff:g id="APPLICATION">%1$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din, inkludert e-post, apper og nettsteder."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Jobbprofilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profilen er koblet til <xliff:g id="APPLICATION">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-poster, apper og nettsteder.\n\nTa kontakt med administratoren hvis du vil ha mer informasjon."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Jobbprofilen din administreres av <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profilen er koblet til <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, som kan overvåke nettverksaktiviteten din på jobben, inkludert e-poster, apper og nettsteder.\n\nDu er også koblet til <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, som kan overvåke den personlige nettverksaktiviteten din."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Låst opp for <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Enheten forblir låst til du låser den opp manuelt"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Motta varsler raskere"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Se dem før du låser opp"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Til <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Behold"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Erstatt"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apper kjører i bakgrunnen"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Trykk for detaljer om batteri- og databruk"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index f23d2e4..ab31f82 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> सम्म"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"राख्नुहोस्"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"प्रतिस्थापन गर्नुहोस्"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"पृष्ठभूमिमा चल्ने अनुप्रयोगहरू"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"ब्याट्री र डेटा प्रयोग सम्बन्धी विवरणहरूका लागि ट्याप गर्नुहोस्"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 7f52537..856f172 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Tot <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Behouden"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Vervangen"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apps uitgevoerd op achtergrond"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tik voor informatie over batterij- en datagebruik"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index e973eb4..0a65637 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"ਤੁਸੀਂ <xliff:g id="APPLICATION">%1$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੋ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫ਼ਾਈਲ ਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਇਹ ਪ੍ਰੋਫ਼ਾਈਲ <xliff:g id="APPLICATION">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਹੈ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਕਾਰਜ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।\n\nਹੋਰ ਜਾਣਕਾਰੀ ਲਈ, ਆਪਣੇ ਪ੍ਰਸ਼ਾਸਕ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"ਤੁਹਾਡੇ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="ORGANIZATION">%1$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ। ਪ੍ਰੋਫਾਈਲ <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ ਹੈ, ਜੋ ਈਮੇਲਾਂ, ਐਪਾਂ, ਅਤੇ ਵੈੱਬਸਾਈਟਾਂ ਸਮੇਤ ਤੁਹਾਡੀ ਕਾਰਜ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।\n\nਤੁਸੀਂ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ਨਾਲ ਵੀ ਕਨੈਕਟ ਹੋਂ, ਜੋ ਤੁਹਾਡੀ ਨਿੱਜੀ ਨੈੱਟਵਰਕ ਸਰਗਰਮੀ ਦੀ ਨਿਗਰਾਨੀ ਕਰ ਸਕਦੀ ਹੈ।"</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g> ਲਈ ਅਨਲੌਕ ਕੀਤੀ ਗਈ"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"ਡੀਵਾਈਸ ਲੌਕ ਰਹੇਗੀ ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਮੈਨੂਅਲੀ ਅਨਲੌਕ ਨਹੀਂ ਕਰਦੇ"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"ਤੇਜ਼ੀ ਨਾਲ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਕਰੋ"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"ਅਨਲੌਕ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਉਹਨਾਂ ਨੂੰ ਦੇਖੋ"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> ਤੱਕ"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"ਰੱਖੋ"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"ਬਦਲੋ"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਚੱਲਣ ਵਾਲੀਆਂ ਐਪਾਂ"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"ਬੈਟਰੀ ਅਤੇ ਡੈਟਾ ਉਪਯੋਗ ਸਬੰਧੀ ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index f34e705..b3ccfc6 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -157,7 +157,7 @@
     <string name="accessibility_cell_data" msgid="5326139158682385073">"Mobilna transmisja danych"</string>
     <string name="accessibility_cell_data_on" msgid="5927098403452994422">"Mobilna transmisja danych włączona"</string>
     <string name="accessibility_cell_data_off" msgid="443267573897409704">"Mobilna transmisja danych wyłączona"</string>
-    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Powiązanie Bluetooth."</string>
+    <string name="accessibility_bluetooth_tether" msgid="4102784498140271969">"Thethering przez Bluetooth."</string>
     <string name="accessibility_airplane_mode" msgid="834748999790763092">"Tryb samolotowy."</string>
     <string name="accessibility_vpn_on" msgid="5993385083262856059">"Sieć VPN włączona."</string>
     <string name="accessibility_no_sims" msgid="3957997018324995781">"Brak karty SIM."</string>
@@ -770,8 +770,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Do: <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Zachowaj"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Zastąp"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikacje działające w tle"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Kliknij, by wyświetlić szczegóły wykorzystania baterii i transmisji danych"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index f2b24c7..1089fcf 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Até <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Manter"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Substituir"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apps sendo executados em segundo plano"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tocar para ver detalhes sobre a bateria e o uso de dados"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index f5152ad..9c03091 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Até à(s) <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Manter"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Substituir"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplicações em execução em segundo plano"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Toque para obter detalhes acerca da utilização da bateria e dos dados"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index f2b24c7..1089fcf 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Até <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Manter"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Substituir"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Apps sendo executados em segundo plano"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tocar para ver detalhes sobre a bateria e o uso de dados"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 46d9107..6ac077b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -768,8 +768,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Până la <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Păstrați"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Înlocuiți"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplicațiile rulează în fundal"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Atingeți pentru mai multe detalii privind bateria și utilizarea datelor"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 37755e3..724263c 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -772,8 +772,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"До <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Сохранить"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Заменить"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Приложения, работающие в фоновом режиме"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Нажмите, чтобы увидеть данные об энергопотреблении и объеме трафика"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 200bb29..5024bfc 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> දක්වා"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"තබන්න"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"ප්‍රතිස්ථාපනය"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"පසුබිමින් ධාවනය වන යෙදුම්"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"බැටරි හා දත්ත භාවිතය පිළිබඳව විස්තර සඳහා තට්ටු කරන්න"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index b265cc7..1ef815c 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -472,8 +472,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Ste pripojený/-á k aplikácii <xliff:g id="APPLICATION">%1$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti vrátane e-mailových správ, aplikácií a webových stránok."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane správ, aplikácií a webových stránok.\n\nĎalšie informácie vám poskytne správca."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Váš pracovný profil spravuje organizácia <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Je pripojený k aplikácii <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ktorá môže sledovať vašu pracovnú aktivitu v sieti vrátane správ, aplikácií a webových stránok.\n\nPripojili ste sa k aplikácii <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ktorá môže sledovať vašu osobnú aktivitu v sieti."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Odomknuté pre používateľa <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Zariadenie zostane uzamknuté, dokým ho ručne neodomknete."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Získavať upozornenia rýchlejšie"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Zobraziť pred odomknutím"</string>
@@ -773,8 +772,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Do <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Ponechať"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Nahradiť"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikácie sú spustené na pozadí"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Klepnutím zobrazíte podrobnosti o batérii a spotrebe dát"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 5c99d97..7336185 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -472,8 +472,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Povezani ste z aplikacijo <xliff:g id="APPLICATION">%1$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan z aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nZa več informacij se obrnite na skrbnika."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Delovni profil upravlja organizacija <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil je povezan z aplikacijo <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ki lahko nadzira vašo delovno omrežno dejavnost, vključno z e-pošto, aplikacijami in spletnimi mesti.\n\nPovezani ste tudi z aplikacijo <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ki lahko nadzira vašo osebno omrežno dejavnost."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Odklenjeno za uporabnika <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Naprava bo ostala zaklenjena, dokler je ročno ne odklenete."</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Hitrejše prejemanje obvestil"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Oglejte si jih pred odklepanjem"</string>
@@ -773,8 +772,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Do <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Obdrži"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Zamenjaj"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikacije, ki se izvajajo v ozadju"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Dotaknite se za prikaz podrobnosti porabe akumulatorja in prenosa podatkov"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index edd78f5..b8c5737 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Deri në <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Mbaj"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Zëvendëso"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Aplikacionet që ekzekutohen në sfond"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Trokit për detaje për baterinë dhe përdorimin e të dhënave"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 5bf7300..f4ee432 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -400,7 +400,7 @@
     <string name="user_logout_notification_text" msgid="3350262809611876284">"Одјавите актуелног корисника"</string>
     <string name="user_logout_notification_action" msgid="1195428991423425062">"ОДЈАВИ КОРИСНИКА"</string>
     <string name="user_add_user_title" msgid="4553596395824132638">"Додајете новог корисника?"</string>
-    <string name="user_add_user_message_short" msgid="2161624834066214559">"Када додате новог корисника, та особа треба да подеси сопствени простор.\n\nСваки корисник може да ажурира апликације за све остале кориснике."</string>
+    <string name="user_add_user_message_short" msgid="2161624834066214559">"Када додате новог корисника, та особа треба да подеси свој простор.\n\nСваки корисник може да ажурира апликације за све остале кориснике."</string>
     <string name="user_remove_user_title" msgid="4681256956076895559">"Желите ли да уклоните корисника?"</string>
     <string name="user_remove_user_message" msgid="1453218013959498039">"Све апликације и подаци овог корисника ће бити избрисани."</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"Уклони"</string>
@@ -468,8 +468,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Повезани сте са апликацијом <xliff:g id="APPLICATION">%1$s</xliff:g>, која може да надгледа активности на личној мрежи, укључујући имејлове, апликације и веб-сајтове."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nВише информација потражите од администратора."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Профилом за Work управља <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Повезан је са апликацијом <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, која може да надгледа активности на пословној мрежи, укључујући имејлове, апликације и веб-сајтове.\n\nПовезани сте и са апликацијом <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, која може да надгледа активности на личној мрежи."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Откључано за корисника <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Уређај ће остати закључан док га не откључате ручно"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Брже добијајте обавештења"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Прегледајте их пре откључавања"</string>
@@ -592,8 +591,8 @@
     <string name="keyboard_key_dpad_left" msgid="1346446024676962251">"Тастер са стрелицом налево"</string>
     <string name="keyboard_key_dpad_right" msgid="3317323247127515341">"Тастер са стрелицом надесно"</string>
     <string name="keyboard_key_dpad_center" msgid="2566737770049304658">"Тастер са централном стрелицом"</string>
-    <string name="keyboard_key_tab" msgid="3871485650463164476">"Табулатор"</string>
-    <string name="keyboard_key_space" msgid="2499861316311153293">"Тастер за размак"</string>
+    <string name="keyboard_key_tab" msgid="3871485650463164476">"Tab"</string>
+    <string name="keyboard_key_space" msgid="2499861316311153293">"Размак"</string>
     <string name="keyboard_key_enter" msgid="5739632123216118137">"Enter"</string>
     <string name="keyboard_key_backspace" msgid="1559580097512385854">"Тастер за брисање уназад"</string>
     <string name="keyboard_key_media_play_pause" msgid="3861975717393887428">"Тастер за репродукцију/паузирање"</string>
@@ -659,7 +658,7 @@
   </string-array>
     <string name="menu_ime" msgid="4998010205321292416">"Пребацивач за тастатуру"</string>
     <string name="save" msgid="2311877285724540644">"Сачувај"</string>
-    <string name="reset" msgid="2448168080964209908">"Поново постави"</string>
+    <string name="reset" msgid="2448168080964209908">"Ресетуј"</string>
     <string name="adjust_button_width" msgid="6138616087197632947">"Прилагоди ширину дугмета"</string>
     <string name="clipboard" msgid="1313879395099896312">"Привремена меморија"</string>
     <string name="accessibility_key" msgid="5701989859305675896">"Прилагођено дугме за навигацију"</string>
@@ -767,8 +766,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"До <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Задржи"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Замени"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Апликације покренуте у позадини"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Додирните да бисте прегледали детаље о батерији и потрошњи података"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 611e3e9..99e8f32 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Till <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Behåll"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Ersätt"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Appar körs i bakgrunden"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Tryck för information om batteri- och dataanvändning"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d3fc010..d572645 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"Umeunganishwa kwenye <xliff:g id="APPLICATION">%1$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako, ikiwa ni pamoja na barua pepe, programu na tovuti."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu umeunganishwa kwenye <xliff:g id="APPLICATION">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli za mtandao wako wa kazini, ikiwa ni pamoja na barua pepe, programu na tovuti.\n\n Wasiliana na msimamizi wako kwa maelezo zaidi."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Wasifu wako wa kazini unasimamiwa na <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Wasifu umeunganishwa kwenye <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, ambayo inaweza kufuatilia shughuli zako kwenye mtandao wa kazini, ikiwa ni pamoja na barua pepe, programu na tovuti.\n\n Umeunganishwa pia kwenye  <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, ambayo inaweza kufuatilia shughuli zako kwenye mtandao wa binafsi."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"Imefunguliwa kwa ajili ya <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Kifaa kitaendelea kuwa katika hali ya kufungwa hadi utakapokifungua mwenyewe"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Pata arifa kwa haraka"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Zitazame kabla hujafungua"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Hadi <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Usibadilishe"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Badilisha"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Programu zinatumika chinichini"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Gonga ili upate maelezo kuhusu betri na matumizi ya data"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index e11bcd2..6f014af 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> வரை"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"வைத்திரு"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"மாற்று"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"பின்னணியில் இயங்கும் பயன்பாடுகள்"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"பேட்டரி மற்றும் தரவு உபயோகம் குறித்த விவரங்களுக்கு, தட்டவும்"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index a4bc497..7d5d769 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"మీరు <xliff:g id="APPLICATION">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమరింత సమాచారం కోసం, మీ నిర్వాహకులను సంప్రదించండి."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"మీ కార్యాలయ ప్రొఫైల్ <xliff:g id="ORGANIZATION">%1$s</xliff:g> నిర్వహణలో ఉంది. ఇమెయిల్‌లు, అనువర్తనాలు మరియు వెబ్‌సైట్‌లతో సహా మీ కార్యాలయ నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>కి ప్రొఫైల్ కనెక్ట్ చేయబడింది.\n\nమీ వ్యక్తిగత నెట్‌వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>కి కూడా మీరు కనెక్ట్ చేయబడ్డారు."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g> కోసం అన్‌లాక్ చేయబడింది"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"మీరు మాన్యువల్‌గా అన్‌లాక్ చేస్తే మినహా పరికరం లాక్ చేయబడి ఉంటుంది"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"నోటిఫికేషన్‌లను వేగంగా పొందండి"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"వీటిని మీరు అన్‌లాక్ చేయకముందే చూడండి"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> వరకు"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"ఉంచు"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"భర్తీ చేయి"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"నేపథ్యంలో అమలు అవుతున్న ఆప్‌లు"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"బ్యాటరీ మరియు డేటా వినియోగ వివరాల కోసం నొక్కండి"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 4859efb..76d2b8e 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"จนถึง <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"เก็บไว้"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"แทนที่"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"แอปที่กำลังทำงานในเบื้องหลัง"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"แตะเพื่อดูรายละเอียดเกี่ยวกับแบตเตอรี่และปริมาณการใช้อินเทอร์เน็ต"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index f23443e..5c4647e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Hanggang <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Panatilihin"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Palitan"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Tumatakbo ang mga app sa background"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"I-tap para sa mga detalye tungkol sa paggamit ng baterya at data"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 8f536f0..dff3481 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"E-postalarınız, uygulamalarınız ve web siteleriniz dahil olmak üzere kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%1$s</xliff:g> uygulamasına bağlısınız."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. Profil; e-postalar, uygulamalar ve web siteleri de dahil olmak üzere iş ağı etkinliğinizi izleyebilen <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasına bağlı.\n\nDaha fazla bilgi için yöneticinize başvurun."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"İş profiliniz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tarafından yönetiliyor. Profil; e-postalar, uygulamalar ve web siteleri de dahil olmak üzere iş ağı etkinliğinizi izleyebilen <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> uygulamasına bağlı.\n\nAyrıca, kişisel ağ etkinliğinizi izleyebilen <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> uygulamasına bağlısınız."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g> için kilit açıldı"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Cihazınızın kilidini manuel olarak açmadıkça cihaz kilitli kalacak"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Bildirimleri daha hızlı alın"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Kilidi açmadan bildirimleri görün"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Bitiş: <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Koru"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Değiştir"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Uygulamalar arka planda çalışıyor"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Pil ve veri kullanımı ile ilgili ayrıntılar için dokunun"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index caf58b8..2119c40 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -772,8 +772,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"До <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Залишити"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Замінити"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Додатки, які працюють у фоновому режимі"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Торкніться, щоб переглянути інформацію про використання заряду акумулятора та даних"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 4734422..e47ccb6 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"آپ <xliff:g id="APPLICATION">%1$s</xliff:g> سے منسلک ہیں، جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے نجی نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ پروفائل <xliff:g id="APPLICATION">%2$s</xliff:g> سے منسلک ہے جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے دفتری نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nمزید معلومات کیلئے اپنے منتظم سے رابطہ کریں۔"</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"آپ کا دفتری پروفائل <xliff:g id="ORGANIZATION">%1$s</xliff:g> کے زیر انتظام ہے۔ پروفائل <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> سے منسلک ہے جو ای میلز، ایپس اور ویب سائٹس سمیت آپ کے دفتری نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔\n\nآپ <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> سے بھی منسلک ہیں، جو آپ کے ذاتی نیٹ ورک کی سرگرمی مانیٹر کر سکتی ہے۔"</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g> کے لیے غیر مقفل کر دیا گیا"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"آلہ اس وقت تک مقفل رہے گا جب تک آپ دستی طور پر اسے غیر مقفل نہ کریں"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"تیزی سے اطلاعات حاصل کریں"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"غیر مقفل کرنے سے پہلے انہیں دیکھیں"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> تک"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"رکھیں"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"بدلیں"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"ایپس پس منظر میں چل رہی ہیں"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"بیٹری اور ڈیٹا استعمال کے بارے میں تفصیلات کے لیے تھپتھپائیں"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 7e2de2e..2e39189 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -468,8 +468,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"<xliff:g id="APPLICATION">%1$s</xliff:g> ilovasi ishga tushirilgan. U internetdagi harakatlaringiz, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin."</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"Ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasi ish tarmog‘idagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nBatafsil axborot olish uchun administrator bilan bog‘laning."</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"Ishchi profilingiz <xliff:g id="ORGANIZATION">%1$s</xliff:g> tomonidan boshqariladi. <xliff:g id="APPLICATION_WORK">%2$s</xliff:g> ilovasi ish tarmog‘idagi, jumladan, e-pochta, ilova va veb-saytlardagi xatti-harakatlaringizni kuzatishi mumkin.\n\nShuningdek, <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g> ilovasi ham shaxsiy tarmoqdagi harakatlaringizni kuzatishi mumkin."</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"<xliff:g id="USER_NAME">%1$s</xliff:g> uchun qulfdan chiqarilgan"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"Qurilma qo‘lda qulfdan chiqarilmaguncha qulflangan holatda qoladi"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"Bildirishnomalarni tezroq oling"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"Ularni qulfdan chiqarishdan oldin ko‘ring"</string>
@@ -765,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"<xliff:g id="ID_1">%s</xliff:g> gacha"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Saqlab qolish"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Almashtirish"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Fonda ishlayotgan ilovalar"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Batareya va trafik sarfiga oid tafsilotlarni olish uchun ustiga bosing"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f313c44..347317e 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -764,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Cho tới <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Giữ"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Thay thế"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Ứng dụng đang chạy trong nền"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Nhấn để biết chi tiết về pin và mức sử dụng dữ liệu"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 55e52eb..0ad9bfe 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已连接到<xliff:g id="APPLICATION">%1$s</xliff:g>,该应用可以监控您的个人网络活动,包括收发电子邮件、使用应用和浏览网站。"</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"您的工作资料由“<xliff:g id="ORGANIZATION">%1$s</xliff:g>”负责管理,且已连接到“<xliff:g id="APPLICATION">%2$s</xliff:g>”(该应用能够监控您的工作网络活动,其中包括收发电子邮件、使用应用和浏览网站)。\n\n如需更多信息,请与您的管理员联系。"</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"您的工作资料由“<xliff:g id="ORGANIZATION">%1$s</xliff:g>”负责管理,且已连接到“<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>”(该应用能够监控您的工作网络活动,其中包括收发电子邮件、使用应用和浏览网站)。\n\n此外,您还连接到了“<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>”(该应用能够监控您的个人网络活动)。"</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"已为<xliff:g id="USER_NAME">%1$s</xliff:g>解锁"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"在您手动解锁之前,设备会保持锁定状态"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"更快捷地查看通知"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"无需解锁即可查看通知"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"直到<xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"保留"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"替换"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"在后台运行的应用"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"点按即可详细了解电量和流量消耗情况"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index e4cd9a5..e526bb7 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -468,8 +468,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"您已連接至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,此應用程式可以監控您的個人網絡活動,包括電郵、應用程式及網站。"</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。設定檔已連結至「<xliff:g id="APPLICATION">%2$s</xliff:g>」,此應用程式可以監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n如需瞭解詳情,請聯絡您的管理員。"</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"您的工作設定檔由<xliff:g id="ORGANIZATION">%1$s</xliff:g>管理。設定檔已連結至「<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>」,此應用程式可以監控您的工作網絡活動,包括電郵、應用程式和網站。\n\n您亦已連結至「<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>」,此應用程式可以監控您的個人網絡活動。"</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"已為<xliff:g id="USER_NAME">%1$s</xliff:g>解鎖"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"裝置將保持上鎖,直到您手動解鎖"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"更快取得通知"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"解鎖前顯示"</string>
@@ -765,8 +764,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"直至<xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"保留"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"取代"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"正在背景中執行的應用程式"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"輕按即可查看電池和數據用量詳情"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 6ec8a36..3bfae88 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -466,8 +466,7 @@
     <string name="branded_monitoring_description_app_personal" msgid="2669518213949202599">"由於你已連結至「<xliff:g id="APPLICATION">%1$s</xliff:g>」,你的個人網路活動 (包括收發電子郵件、使用應用程式及瀏覽網站) 可能會受到這個應用程式監控。"</string>
     <string name="monitoring_description_app_work" msgid="4612997849787922906">"你的 Work 設定檔是由「<xliff:g id="ORGANIZATION">%1$s</xliff:g>」所管理。由於該設定檔已連結至「<xliff:g id="APPLICATION">%2$s</xliff:g>」,因此你的網路活動 (包括收發電子郵件、使用應用程式和瀏覽網站) 可能會受到這個應用程式監控。\n\n如要瞭解詳情,請與你的管理員聯絡。"</string>
     <string name="monitoring_description_app_personal_work" msgid="5664165460056859391">"你的 Work 設定檔是由「<xliff:g id="ORGANIZATION">%1$s</xliff:g>」所管理。由於該設定檔已連結至「<xliff:g id="APPLICATION_WORK">%2$s</xliff:g>」,因此你的網路活動 (包括收發電子郵件、使用應用程式和瀏覽網站) 可能會受到這個應用程式監控。\n\n此外,你還與「<xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>」建立了連結,因此你的個人網路活動也可能會受到該應用程式監控。"</string>
-    <!-- no translation found for keyguard_indication_trust_granted (4985003749105182372) -->
-    <skip />
+    <string name="keyguard_indication_trust_granted" msgid="4985003749105182372">"已為<xliff:g id="USER_NAME">%1$s</xliff:g>解鎖"</string>
     <string name="keyguard_indication_trust_disabled" msgid="7412534203633528135">"在你手動解鎖前,裝置將保持鎖定狀態"</string>
     <string name="hidden_notifications_title" msgid="7139628534207443290">"更快取得通知"</string>
     <string name="hidden_notifications_text" msgid="2326409389088668981">"解鎖前顯示"</string>
@@ -763,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"直到 <xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"保留"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"取代"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"在背景執行的應用程式"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"輕觸即可取得電池和數據用量的詳細資料"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 6fe7aa9..3f0dde6 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -762,8 +762,6 @@
     <string name="qs_dnd_until" msgid="3469471136280079874">"Kuze kube-<xliff:g id="ID_1">%s</xliff:g>"</string>
     <string name="qs_dnd_keep" msgid="1825009164681928736">"Gcina"</string>
     <string name="qs_dnd_replace" msgid="8019520786644276623">"Buyisela"</string>
-    <!-- no translation found for running_foreground_services_title (381024150898615683) -->
-    <skip />
-    <!-- no translation found for running_foreground_services_msg (6326247670075574355) -->
-    <skip />
+    <string name="running_foreground_services_title" msgid="381024150898615683">"Izinhlelo zokusebenza zisebenza ngasemuva"</string>
+    <string name="running_foreground_services_msg" msgid="6326247670075574355">"Thepha ngemininingwane ekusetshenzisweni kwebhethri nedatha"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/arrays_tv.xml b/packages/SystemUI/res/values/arrays_tv.xml
index e52c5db..7541b0e 100644
--- a/packages/SystemUI/res/values/arrays_tv.xml
+++ b/packages/SystemUI/res/values/arrays_tv.xml
@@ -31,5 +31,6 @@
         <item>com.google.android.katniss.setting/.SpeechSettingsActivity</item>
         <item>com.google.android.katniss.setting/.SearchSettingsActivity</item>
         <item>com.google.android.gsf.notouch/.UsageDiagnosticsSettingActivity</item>
+        <item>com.google.android.tvlauncher/.notifications.NotificationsSidePanelActivity</item>
     </string-array>
 </resources>
diff --git a/packages/SystemUI/res/values/config_tv.xml b/packages/SystemUI/res/values/config_tv.xml
index 40e3b12..ffd58dc 100644
--- a/packages/SystemUI/res/values/config_tv.xml
+++ b/packages/SystemUI/res/values/config_tv.xml
@@ -17,17 +17,9 @@
 <resources>
     <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
          when the PIP menu is shown with settings. -->
-    <string translatable="false" name="pip_settings_bounds">"662 54 1142 324"</string>
+    <string translatable="false" name="pip_settings_bounds">"662 756 1142 1026"</string>
 
     <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
          when the PIP menu is shown in center. -->
     <string translatable="false" name="pip_menu_bounds">"596 280 1324 690"</string>
-
-    <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
-         when the PIP is shown in Recents without focus. -->
-    <string translatable="false" name="pip_recents_bounds">"800 54 1120 234"</string>
-
-    <!-- Bounds [left top right bottom] on screen for picture-in-picture (PIP) windows,
-         when the PIP is shown in Recents with focus. -->
-    <string translatable="false" name="pip_recents_focused_bounds">"775 54 1145 262"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/ids.xml b/packages/SystemUI/res/values/ids.xml
index fc0c82c..3c6ad23 100644
--- a/packages/SystemUI/res/values/ids.xml
+++ b/packages/SystemUI/res/values/ids.xml
@@ -45,6 +45,7 @@
     <item type="id" name="shadow_alpha_animator_start_value_tag"/>
     <item type="id" name="doze_saved_filter_tag"/>
     <item type="id" name="qs_icon_tag"/>
+    <item type="id" name="qs_slash_tag"/>
     <item type="id" name="scrim"/>
     <item type="id" name="scrim_target"/>
     <item type="id" name="scrim_alpha_start"/>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 1ea4f83..bd539ea 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2036,7 +2036,9 @@
     <!-- Title of the "running foreground services" dialog. [CHAR LIMIT=NONE] -->
     <string name="running_foreground_services_title">Apps running in background</string>
 
-    <!-- Title of the "running foreground services" dialog. [CHAR LIMIT=NONE] -->
+    <!-- Descriptive text of an item in the "running foreground services" dialog, telling the
+        user what will happen when they tap on that item (which is an application that has
+        been identified for them as running). [CHAR LIMIT=NONE] -->
     <string name="running_foreground_services_msg">Tap for details on battery and data usage</string>
 
 </resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index e578068..a9bdb71 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -17,6 +17,14 @@
  */
 -->
 <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+
+    <!-- Picture-in-Picture (PIP) notification -->
+    <!-- Title for the notification channel for TV PIP controls. [CHAR LIMIT=NONE] -->
+    <string name="notification_channel_tv_pip">Picture-in-Picture</string>
+    <!-- Title of the picture-in-picture (PIP) notification title
+         when the media doesn't have title [CHAR LIMIT=NONE] -->
+    <string name="pip_notification_unknown_title">(No title program)</string>
+
     <!-- Picture-in-Picture (PIP) menu -->
     <eat-comment />
     <!-- Button to close picture-in-picture (PIP) in PIP menu [CHAR LIMIT=30] -->
diff --git a/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
index 49e780c..9d286cf 100644
--- a/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/ForegroundServicesDialog.java
@@ -66,7 +66,7 @@
     private DialogInterface.OnClickListener mAppClickListener =
             new DialogInterface.OnClickListener() {
                 public void onClick(DialogInterface dialog, int which) {
-                    String pkg = mPackages[which];
+                    String pkg = mAdapter.getItem(which).packageName;
                     Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                     intent.setData(Uri.fromParts("package", pkg, null));
                     startActivity(intent);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index df03fdc..bdc0871 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -107,12 +107,12 @@
         }
 
         @Override
-        public void onPinnedActivityRestartAttempt() {
+        public void onPinnedActivityRestartAttempt(boolean clearedTask) {
             if (!checkCurrentUserId(false /* debug */)) {
                 return;
             }
 
-            mTouchHandler.getMotionHelper().expandPip();
+            mTouchHandler.getMotionHelper().expandPip(clearedTask /* skipAnimation */);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index d5cf1dd..5afa53f 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -132,9 +132,6 @@
                 }
                 case MESSAGE_EXPAND_PIP: {
                     mListeners.forEach(l -> l.onPipExpand());
-                    // Preemptively mark the menu as invisible once we expand the PiP, but don't
-                    // resize as we will be animating the stack
-                    onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
                     break;
                 }
                 case MESSAGE_MINIMIZE_PIP: {
@@ -143,9 +140,6 @@
                 }
                 case MESSAGE_DISMISS_PIP: {
                     mListeners.forEach(l -> l.onPipDismiss());
-                    // Preemptively mark the menu as invisible once we dismiss the PiP, but don't
-                    // resize as we'll be removing the stack in place
-                    onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
                     break;
                 }
                 case MESSAGE_SHOW_MENU: {
@@ -308,6 +302,15 @@
     }
 
     /**
+     * Preemptively mark the menu as invisible, used when we are directly manipulating the pinned
+     * stack and don't want to trigger a resize which can animate the stack in a conflicting way
+     * (ie. when manually expanding or dismissing).
+     */
+    public void hideMenuWithoutResize() {
+        onMenuStateChanged(MENU_STATE_NONE, false /* resize */);
+    }
+
+    /**
      * @return the current menu state.
      */
     public int getMenuState() {
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index fc52a2e..590e3c6 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -77,6 +77,7 @@
     private SurfaceFlingerVsyncChoreographer mVsyncChoreographer;
     private Handler mHandler;
 
+    private PipMenuActivityController mMenuController;
     private PipSnapAlgorithm mSnapAlgorithm;
     private FlingAnimationUtils mFlingAnimationUtils;
 
@@ -93,10 +94,12 @@
             };
 
     public PipMotionHelper(Context context, IActivityManager activityManager,
-            PipSnapAlgorithm snapAlgorithm, FlingAnimationUtils flingAnimationUtils) {
+            PipMenuActivityController menuController, PipSnapAlgorithm snapAlgorithm,
+            FlingAnimationUtils flingAnimationUtils) {
         mContext = context;
         mHandler = BackgroundThread.getHandler();
         mActivityManager = activityManager;
+        mMenuController = menuController;
         mSnapAlgorithm = snapAlgorithm;
         mFlingAnimationUtils = flingAnimationUtils;
         mVsyncChoreographer = new SurfaceFlingerVsyncChoreographer(mHandler, mContext.getDisplay(),
@@ -140,14 +143,26 @@
      * Resizes the pinned stack back to fullscreen.
      */
     void expandPip() {
+        expandPip(false /* skipAnimation */);
+    }
+
+    /**
+     * Resizes the pinned stack back to fullscreen.
+     */
+    void expandPip(boolean skipAnimation) {
         cancelAnimations();
+        mMenuController.hideMenuWithoutResize();
         mHandler.post(() -> {
             try {
-                mActivityManager.resizeStack(PINNED_STACK_ID, null /* bounds */,
-                        true /* allowResizeInDockedMode */, true /* preserveWindows */,
-                        true /* animate */, EXPAND_STACK_TO_FULLSCREEN_DURATION);
+                if (skipAnimation) {
+                    mActivityManager.moveTasksToFullscreenStack(PINNED_STACK_ID, true /* onTop */);
+                } else {
+                    mActivityManager.resizeStack(PINNED_STACK_ID, null /* bounds */,
+                            true /* allowResizeInDockedMode */, true /* preserveWindows */,
+                            true /* animate */, EXPAND_STACK_TO_FULLSCREEN_DURATION);
+                }
             } catch (RemoteException e) {
-                Log.e(TAG, "Error showing PiP menu activity", e);
+                Log.e(TAG, "Error expanding PiP activity", e);
             }
         });
     }
@@ -157,6 +172,7 @@
      */
     void dismissPip() {
         cancelAnimations();
+        mMenuController.hideMenuWithoutResize();
         mHandler.post(() -> {
             try {
                 mActivityManager.removeStack(PINNED_STACK_ID);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
index 9c7e3986..71d3d35 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java
@@ -191,8 +191,8 @@
         mGestures = new PipTouchGesture[] {
                 mDefaultMovementGesture
         };
-        mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mSnapAlgorithm,
-                mFlingAnimationUtils);
+        mMotionHelper = new PipMotionHelper(mContext, mActivityManager, mMenuController,
+                mSnapAlgorithm, mFlingAnimationUtils);
         mExpandedShortestEdgeSize = context.getResources().getDimensionPixelSize(
                 R.dimen.pip_expanded_shortest_edge_size);
 
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index 657f08b..6667b71 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -61,7 +61,8 @@
  */
 public class PipManager implements BasePipManager {
     private static final String TAG = "PipManager";
-    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
     private static final String SETTINGS_PACKAGE_AND_CLASS_DELIMITER = "/";
 
     private static PipManager sPipManager;
@@ -122,6 +123,7 @@
     private ComponentName mPipComponentName;
     private MediaController mPipMediaController;
     private String[] mLastPackagesResourceGranted;
+    private PipNotification mPipNotification;
 
     private final PinnedStackListener mPinnedStackListener = new PinnedStackListener();
 
@@ -246,6 +248,8 @@
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to register pinned stack listener", e);
         }
+
+        mPipNotification = new PipNotification(context);
     }
 
     private void loadConfigurationsAndApply() {
@@ -267,6 +271,7 @@
      */
     public void onConfigurationChanged() {
         loadConfigurationsAndApply();
+        mPipNotification.onConfigurationChanged(mContext);
     }
 
     /**
@@ -345,7 +350,7 @@
      * @param state In Pip state also used to determine the new size for the Pip.
      */
     void resizePinnedStack(int state) {
-        if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state);
+        if (DEBUG) Log.d(TAG, "resizePinnedStack() state=" + state, new Exception());
         boolean wasStateNoPip = (mState == STATE_NO_PIP);
         mResumeResizePinnedStackRunnable = state;
         for (int i = mListeners.size() - 1; i >= 0; --i) {
@@ -511,8 +516,8 @@
 
     /**
      * Returns the PIPed activity's playback state.
-     * This returns one of {@link PLAYBACK_STATE_PLAYING}, {@link PLAYBACK_STATE_PAUSED},
-     * or {@link PLAYBACK_STATE_UNAVAILABLE}.
+     * This returns one of {@link #PLAYBACK_STATE_PLAYING}, {@link #PLAYBACK_STATE_PAUSED},
+     * or {@link #PLAYBACK_STATE_UNAVAILABLE}.
      */
     int getPlaybackState() {
         if (mPipMediaController == null || mPipMediaController.getPlaybackState() == null) {
@@ -625,7 +630,7 @@
         }
 
         @Override
-        public void onPinnedActivityRestartAttempt() {
+        public void onPinnedActivityRestartAttempt(boolean clearedTask) {
             if (DEBUG) Log.d(TAG, "onPinnedActivityRestartAttempt()");
             if (!checkCurrentUserId(DEBUG)) {
                 return;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
new file mode 100644
index 0000000..727eb5a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -0,0 +1,225 @@
+/*
+ * 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.pip.tv;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
+import android.media.MediaMetadata;
+import android.media.session.MediaController;
+import android.media.session.PlaybackState;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+
+import com.android.systemui.util.NotificationChannels;
+import com.android.systemui.R;
+import com.android.internal.messages.nano.SystemMessageProto.SystemMessage;
+
+/**
+ * A notification that informs users that PIP is running and also provides PIP controls.
+ * <p>Once it's created, it will manage the PIP notification UI by itself except for handling
+ * configuration changes.
+ */
+public class PipNotification {
+    private static final String TAG = "PipNotification";
+    private static final boolean DEBUG = PipManager.DEBUG;
+
+    private static final String ACTION_MENU = "PipNotification.menu";
+    private static final String ACTION_CLOSE = "PipNotification.close";
+
+    private final PipManager mPipManager = PipManager.getInstance();
+
+    private final NotificationManager mNotificationManager;
+    private final Notification.Builder mNotificationBuilder;
+
+    private MediaController mMediaController;
+    private String mDefaultTitle;
+    private Icon mDefaultIcon;
+
+    private boolean mNotified;
+    private String mTitle;
+    private Bitmap mArt;
+
+    private PipManager.Listener mPipListener = new PipManager.Listener() {
+        @Override
+        public void onPipEntered() {
+            updateMediaControllerMetadata();
+            notifyPipNotification();
+        }
+
+        @Override
+        public void onPipActivityClosed() {
+            dismissPipNotification();
+        }
+
+        @Override
+        public void onShowPipMenu() {
+            // no-op.
+        }
+
+        @Override
+        public void onMoveToFullscreen() {
+            dismissPipNotification();
+        }
+
+        @Override
+        public void onPipResizeAboutToStart() {
+            // no-op.
+        }
+    };
+
+    private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
+        @Override
+        public void onPlaybackStateChanged(PlaybackState state) {
+            if (updateMediaControllerMetadata() && mNotified) {
+                // update notification
+                notifyPipNotification();
+            }
+        }
+    };
+
+    private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
+        @Override
+        public void onMediaControllerChanged() {
+            MediaController newController = mPipManager.getMediaController();
+            if (mMediaController == newController) {
+                return;
+            }
+            if (mMediaController != null) {
+                mMediaController.unregisterCallback(mMediaControllerCallback);
+            }
+            mMediaController = newController;
+            if (mMediaController != null) {
+                mMediaController.registerCallback(mMediaControllerCallback);
+            }
+            if (updateMediaControllerMetadata() && mNotified) {
+                // update notification
+                notifyPipNotification();
+            }
+        }
+    };
+
+    private final BroadcastReceiver mEventReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Log.d(TAG, "Received " + intent.getAction() + " from the notification UI");
+            }
+            switch (intent.getAction()) {
+                case ACTION_MENU:
+                    mPipManager.showPictureInPictureMenu();
+                    break;
+                case ACTION_CLOSE:
+                    mPipManager.closePip();
+                    break;
+            }
+        }
+    };
+
+    public PipNotification(Context context) {
+        mNotificationManager = (NotificationManager) context.getSystemService(
+                Context.NOTIFICATION_SERVICE);
+
+        mNotificationBuilder = new Notification.Builder(context, NotificationChannels.TVPIP)
+                .setLocalOnly(true)
+                .setOngoing(false)
+                .setCategory(Notification.CATEGORY_SYSTEM)
+                .extend(new Notification.TvExtender()
+                        .setContentIntent(createPendingIntent(context, ACTION_MENU))
+                        .setDeleteIntent(createPendingIntent(context, ACTION_CLOSE)));
+
+        mPipManager.addListener(mPipListener);
+        mPipManager.addMediaListener(mPipMediaListener);
+
+        IntentFilter intentFilter = new IntentFilter();
+        intentFilter.addAction(ACTION_MENU);
+        intentFilter.addAction(ACTION_CLOSE);
+        context.registerReceiver(mEventReceiver, intentFilter);
+
+        onConfigurationChanged(context);
+    }
+
+    /**
+     * Called by {@link PipManager} when the configuration is changed.
+     */
+    void onConfigurationChanged(Context context) {
+        Resources res = context.getResources();
+        mDefaultTitle = res.getString(R.string.pip_notification_unknown_title);
+        mDefaultIcon = Icon.createWithResource(context,
+                res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
+                        ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr);
+        if (mNotified) {
+            // update notification
+            notifyPipNotification();
+        }
+    }
+
+    private void notifyPipNotification() {
+        mNotified = true;
+        mNotificationBuilder
+                .setShowWhen(true)
+                .setWhen(System.currentTimeMillis())
+                // TODO: Sending bitmap doesn't work in launcher side. Once launcher supports it,
+                // we can set icon.
+                //.setSmallIcon(mArt != null ? Icon.createWithBitmap(mArt) : mDefaultIcon)
+                .setSmallIcon(mDefaultIcon.getResId())
+                .setContentTitle(!TextUtils.isEmpty(mTitle) ? mTitle : mDefaultTitle);
+        mNotificationManager.notify(SystemMessage.NOTE_TV_PIP, mNotificationBuilder.build());
+    }
+
+    private void dismissPipNotification() {
+        mNotified = false;
+        mNotificationManager.cancel(SystemMessage.NOTE_TV_PIP);
+    }
+
+    private boolean updateMediaControllerMetadata() {
+        String title = null;
+        Bitmap art = null;
+        if (mPipManager.getMediaController() != null) {
+            MediaMetadata metadata = mPipManager.getMediaController().getMetadata();
+            if (metadata != null) {
+                title = metadata.getString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE);
+                if (TextUtils.isEmpty(title)) {
+                    title = metadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+                }
+                art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART);
+                if (art == null) {
+                    art = metadata.getBitmap(MediaMetadata.METADATA_KEY_ART);
+                }
+            }
+        }
+        if (!TextUtils.equals(title, mTitle) || art != mArt) {
+            mTitle = title;
+            mArt = art;
+            return true;
+        }
+        return false;
+    }
+
+    private static PendingIntent createPendingIntent(Context context, String action) {
+        return PendingIntent.getBroadcast(context, 0,
+                new Intent(action), PendingIntent.FLAG_CANCEL_CURRENT);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
index 01f8169..d413030 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/SignalTileView.java
@@ -27,6 +27,7 @@
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.SignalState;
 import com.android.systemui.qs.tileimpl.QSIconViewImpl;
+import com.android.systemui.qs.tileimpl.SlashImageView;
 
 /** View that represents a custom quick settings tile for displaying signal info (wifi/cell). **/
 public class SignalTileView extends QSIconViewImpl {
@@ -61,7 +62,7 @@
     @Override
     protected View createIcon() {
         mIconFrame = new FrameLayout(mContext);
-        mSignal = new ImageView(mContext);
+        mSignal = new SlashImageView(mContext);
         mIconFrame.addView(mSignal);
         return mIconFrame;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
new file mode 100644
index 0000000..6fe3c5a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/SlashDrawable.java
@@ -0,0 +1,178 @@
+/*
+ * 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.qs;
+
+import android.annotation.ColorInt;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.res.ColorStateList;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.PorterDuff.Mode;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.util.Log;
+
+public class SlashDrawable extends Drawable {
+
+    private final Path mPath = new Path();
+    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+    private static float[] OFFSET = {
+        1.3f / 24f,-1.3f / 24f
+    };
+    private static float[][] PATH = {
+            {21.9f / 24f, 21.9f / 24f},
+            {2.1f / 24f, 2.1f / 24f},
+            {0.8f / 24f, 3.4f / 24f},
+            {20.6f / 24f, 23.2f / 24f},
+    };
+    private Drawable mDrawable;
+    private float mRotation;
+    private boolean mSlashed;
+    private Mode mTintMode;
+    private ColorStateList mTintList;
+
+    public SlashDrawable(Drawable d) {
+        mDrawable = d;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mDrawable != null ? mDrawable.getIntrinsicHeight(): 0;
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mDrawable != null ? mDrawable.getIntrinsicWidth(): 0;
+    }
+
+    @Override
+    protected void onBoundsChange(Rect bounds) {
+        super.onBoundsChange(bounds);
+        mDrawable.setBounds(bounds);
+    }
+
+    public void setDrawable(Drawable d) {
+        mDrawable = d;
+        mDrawable.setCallback(getCallback());
+        mDrawable.setBounds(getBounds());
+        if (mTintMode != null) mDrawable.setTintMode(mTintMode);
+        if (mTintList != null) mDrawable.setTintList(mTintList);
+        invalidateSelf();
+    }
+
+    public void setRotation(float rotation) {
+        if (mRotation == rotation) return;
+        mRotation = rotation;
+        invalidateSelf();
+    }
+
+    public void setSlashed(boolean slashed) {
+        Log.d("TestTest", "setSlashed " + slashed);
+        if (mSlashed == slashed) return;
+        // TODO: Animate.
+        mSlashed = slashed;
+        invalidateSelf();
+    }
+
+    @Override
+    public void draw(@NonNull Canvas canvas) {
+        canvas.save();
+        Log.d("TestTest", "draw " + mSlashed);
+        if (mSlashed) {
+            Matrix m = new Matrix();
+            int width = getBounds().width();
+            int height = getBounds().height();
+            mPath.reset();
+            mPath.moveTo(scale(PATH[0][0], width), scale(PATH[0][1], height));
+            mPath.lineTo(scale(PATH[1][0], width), scale(PATH[1][1], height));
+            mPath.lineTo(scale(PATH[2][0], width), scale(PATH[2][1], height));
+            mPath.lineTo(scale(PATH[3][0], width), scale(PATH[3][1], height));
+            mPath.close();
+            m = new Matrix();
+            m.setRotate(mRotation, width / 2, height / 2);
+            mPath.transform(m);
+            canvas.drawPath(mPath, mPaint);
+            m = new Matrix();
+            m.setRotate(-mRotation, width / 2, height / 2);
+            mPath.transform(m);
+
+            m = new Matrix();
+            m.setTranslate(scale(OFFSET[0], width), scale(OFFSET[1], height));
+            mPath.transform(m);
+            mPath.moveTo(scale(PATH[0][0], width), scale(PATH[0][1], height));
+            mPath.lineTo(scale(PATH[1][0], width), scale(PATH[1][1], height));
+            mPath.lineTo(scale(PATH[2][0], width), scale(PATH[2][1], height));
+            mPath.lineTo(scale(PATH[3][0], width), scale(PATH[3][1], height));
+            mPath.close();
+            m = new Matrix();
+            m.setRotate(mRotation, width / 2, height / 2);
+            mPath.transform(m);
+            canvas.clipOutPath(mPath);
+        }
+
+        mDrawable.draw(canvas);
+        canvas.restore();
+    }
+
+    private float scale(float frac, int width) {
+        return frac * width;
+    }
+
+    @Override
+    public void setTint(@ColorInt int tintColor) {
+        super.setTint(tintColor);
+        mDrawable.setTint(tintColor);
+        mPaint.setColor(tintColor);
+    }
+
+    @Override
+    public void setTintList(@Nullable ColorStateList tint) {
+        mTintList = tint;
+        super.setTintList(tint);
+        mDrawable.setTintList(tint);
+        mPaint.setColor(tint.getDefaultColor());
+        invalidateSelf();
+    }
+
+    @Override
+    public void setTintMode(@NonNull Mode tintMode) {
+        mTintMode = tintMode;
+        super.setTintMode(tintMode);
+        mDrawable.setTintMode(tintMode);
+    }
+
+    @Override
+    public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
+        mDrawable.setAlpha(alpha);
+        mPaint.setAlpha(alpha);
+    }
+
+    @Override
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
+        mDrawable.setColorFilter(colorFilter);
+        mPaint.setColorFilter(colorFilter);
+    }
+
+    @Override
+    public int getOpacity() {
+        return 255;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 661c921..b39fc11 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -21,7 +21,6 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.graphics.Color;
-import android.graphics.drawable.Animatable;
 import android.graphics.drawable.Animatable2;
 import android.graphics.drawable.Animatable2.AnimationCallback;
 import android.graphics.drawable.Drawable;
@@ -85,7 +84,8 @@
     }
 
     protected void updateIcon(ImageView iv, State state) {
-        if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) {
+        if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))
+                || !Objects.equals(state.slash, iv.getTag(R.id.qs_slash_tag))) {
             boolean shouldAnimate = iv.isShown() && mAnimationEnabled
                     && iv.getDrawable() != null;
             Drawable d = state.icon != null
@@ -96,7 +96,11 @@
                 d.setAutoMirrored(false);
             }
             iv.setImageDrawable(d);
+            if (state.slash != null && iv instanceof SlashImageView) {
+                ((SlashImageView) iv).setState(state.slash);
+            }
             iv.setTag(R.id.qs_icon_tag, state.icon);
+            iv.setTag(R.id.qs_slash_tag, state.slash);
             iv.setPadding(0, padding, 0, padding);
             if (d instanceof Animatable2) {
                 Animatable2 a = (Animatable2) d;
@@ -166,7 +170,7 @@
     }
 
     protected View createIcon() {
-        final ImageView icon = new ImageView(mContext);
+        final ImageView icon = new SlashImageView(mContext);
         icon.setId(android.R.id.icon);
         icon.setScaleType(ScaleType.FIT_CENTER);
         return icon;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
new file mode 100644
index 0000000..603f66b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/SlashImageView.java
@@ -0,0 +1,53 @@
+/*
+ * 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.qs.tileimpl;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.widget.ImageView;
+
+import com.android.systemui.plugins.qs.QSTile.SlashState;
+import com.android.systemui.qs.SlashDrawable;
+
+public class SlashImageView extends ImageView {
+
+    private SlashDrawable mSlash;
+
+    public SlashImageView(Context context) {
+        super(context);
+    }
+
+    private void ensureSlashDrawable() {
+        if (mSlash == null) {
+            mSlash = new SlashDrawable(getDrawable());
+            super.setImageDrawable(mSlash);
+        }
+    }
+
+    @Override
+    public void setImageDrawable(Drawable drawable) {
+        if (mSlash != null) {
+            mSlash.setDrawable(drawable);
+        } else {
+            super.setImageDrawable(drawable);
+        }
+    }
+
+    public void setState(SlashState slashState) {
+        ensureSlashDrawable();
+        mSlash.setRotation(slashState.rotation);
+        mSlash.setSlashed(slashState.isSlashed);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index c5f798e..c0509c1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -29,19 +29,15 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.GlobalSetting;
 import com.android.systemui.qs.QSHost;
-import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 
 /** Quick settings tile: Airplane mode **/
 public class AirplaneModeTile extends QSTileImpl<BooleanState> {
-    private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_signal_airplane_enable_animation,
-                    R.drawable.ic_signal_airplane_disable);
-    private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_signal_airplane_disable_animation,
-                    R.drawable.ic_signal_airplane_enable);
+    private final Icon mIcon =
+            ResourceIcon.get(R.drawable.ic_signal_airplane_disable);
     private final GlobalSetting mSetting;
 
     private boolean mListening;
@@ -90,11 +86,11 @@
         final boolean airplaneMode = value != 0;
         state.value = airplaneMode;
         state.label = mContext.getString(R.string.airplane_mode);
-        if (airplaneMode) {
-            state.icon = mEnable;
-        } else {
-            state.icon = mDisable;
+        state.icon = mIcon;
+        if (state.slash == null) {
+            state.slash = new SlashState();
         }
+        state.slash.isSlashed = !airplaneMode;
         state.state = airplaneMode ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.contentDescription = state.label;
         state.expandedAccessibilityClassName = Switch.class.getName();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 9b20a7a..703be27 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -114,6 +114,10 @@
                 || mController.getBluetoothState() == BluetoothAdapter.STATE_TURNING_ON;
         state.dualTarget = true;
         state.value = enabled;
+        if (state.slash == null) {
+            state.slash = new SlashState();
+        }
+        state.slash.isSlashed = !enabled;
         if (enabled) {
             state.label = null;
             if (connected) {
@@ -137,7 +141,7 @@
             }
             state.state = Tile.STATE_ACTIVE;
         } else {
-            state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_off);
+            state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
             state.label = mContext.getString(R.string.quick_settings_bluetooth_label);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_bluetooth_off);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 5512993..6f28838 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -68,6 +68,7 @@
     private final Callback mCallback = new Callback();
     private final ActivityStarter mActivityStarter;
     private Dialog mDialog;
+    private boolean mRegistered;
 
     public CastTile(QSHost host) {
         super(host);
@@ -146,7 +147,7 @@
                 mDialog = dialog;
             }
             mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_STATUS_BAR_PANEL);
-            mDialog.show();
+            mUiHandler.post(() -> mDialog.show());
             registerReceiver();
             mHost.collapsePanels();
         });
@@ -155,7 +156,13 @@
     private void registerReceiver() {
         mContext.registerReceiverAsUser(mReceiver, UserHandle.CURRENT,
                 new IntentFilter(Intent.ACTION_CLOSE_SYSTEM_DIALOGS), null, null);
-        mDialog.setOnDismissListener(dialog -> mContext.unregisterReceiver(mReceiver));
+        mRegistered = true;
+        mDialog.setOnDismissListener(dialog -> {
+            if (mRegistered) {
+                mContext.unregisterReceiver(mReceiver);
+                mRegistered = false;
+            }
+        });
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 92ff17a1..a4aa262 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -127,13 +127,16 @@
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.value = mDataController.isMobileDataSupported()
                 && mDataController.isMobileDataEnabled();
-        state.icon = ResourceIcon.get(R.drawable.ic_data_unavailable);
         state.state = cb.airplaneModeEnabled || !cb.enabled ? Tile.STATE_UNAVAILABLE
                 : state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        if (state.slash == null) {
+            state.slash = new SlashState();
+        }
+        state.slash.isSlashed = (state.state == Tile.STATE_INACTIVE);
         if (state.state == Tile.STATE_ACTIVE) {
             state.icon = ResourceIcon.get(R.drawable.ic_data_on);
         } else if (state.state == Tile.STATE_INACTIVE) {
-            state.icon = ResourceIcon.get(R.drawable.ic_data_off);
+            state.icon = ResourceIcon.get(R.drawable.ic_data_on);
         } else {
             state.icon = ResourceIcon.get(R.drawable.ic_data_unavailable);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index 5b374b1..97a12c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -25,6 +25,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
+import com.android.systemui.R.drawable;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
@@ -33,12 +34,7 @@
 /** Quick settings tile: Invert colors **/
 public class ColorInversionTile extends QSTileImpl<BooleanState> {
 
-    private final AnimationIcon mEnable
-            = new AnimationIcon(R.drawable.ic_invert_colors_enable_animation,
-            R.drawable.ic_invert_colors_disable);
-    private final AnimationIcon mDisable
-            = new AnimationIcon(R.drawable.ic_invert_colors_disable_animation,
-            R.drawable.ic_invert_colors_enable);
+    private final Icon mIcon = ResourceIcon.get(drawable.ic_invert_colors_disable);
     private final SecureSetting mSetting;
 
     private boolean mListening;
@@ -96,10 +92,14 @@
     protected void handleUpdateState(BooleanState state, Object arg) {
         final int value = arg instanceof Integer ? (Integer) arg : mSetting.getValue();
         final boolean enabled = value != 0;
+        if (state.slash == null) {
+            state.slash = new SlashState();
+        }
         state.value = enabled;
+        state.slash.isSlashed = !state.value;
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
         state.label = mContext.getString(R.string.quick_settings_inversion_label);
-        state.icon = enabled ? mEnable : mDisable;
+        state.icon = mIcon;
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.contentDescription = state.label;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index ecbc4f7..8c6363a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -27,7 +27,6 @@
 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.net.Uri;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.provider.Settings.Global;
@@ -72,12 +71,7 @@
     private static final QSTile.Icon TOTAL_SILENCE =
             ResourceIcon.get(R.drawable.ic_qs_dnd_on_total_silence);
 
-    private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_dnd_disable_animation,
-                    R.drawable.ic_qs_dnd_off);
-    private final AnimationIcon mDisableTotalSilence =
-            new AnimationIcon(R.drawable.ic_dnd_total_silence_disable_animation,
-                    R.drawable.ic_qs_dnd_off);
+    private final Icon mDisable = ResourceIcon.get(R.drawable.ic_qs_dnd_off);
 
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
@@ -167,9 +161,11 @@
         final int zen = arg instanceof Integer ? (Integer) arg : mController.getZen();
         final boolean newValue = zen != ZEN_MODE_OFF;
         final boolean valueChanged = state.value != newValue;
+        if (state.slash == null) state.slash = new SlashState();
         state.dualTarget = true;
         state.value = newValue;
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
+        state.slash.isSlashed = !state.value;
         checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
         switch (zen) {
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
@@ -191,7 +187,7 @@
                         R.string.accessibility_quick_settings_dnd_alarms_on);
                 break;
             default:
-                state.icon = TOTAL_SILENCE.equals(state.icon) ? mDisableTotalSilence : mDisable;
+                state.icon = mDisable;
                 state.label = mContext.getString(R.string.quick_settings_dnd_label);
                 state.contentDescription = mContext.getString(
                         R.string.accessibility_quick_settings_dnd);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 6d2aa90..b436e17 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -23,12 +23,11 @@
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
-import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.qs.QSHost;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
+import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.FlashlightController;
 
@@ -36,12 +35,7 @@
 public class FlashlightTile extends QSTileImpl<BooleanState> implements
         FlashlightController.FlashlightListener {
 
-    private final AnimationIcon mEnable
-            = new AnimationIcon(R.drawable.ic_signal_flashlight_enable_animation,
-            R.drawable.ic_signal_flashlight_disable);
-    private final AnimationIcon mDisable
-            = new AnimationIcon(R.drawable.ic_signal_flashlight_disable_animation,
-            R.drawable.ic_signal_flashlight_enable);
+    private final Icon mIcon = ResourceIcon.get(R.drawable.ic_signal_flashlight_disable);
     private final FlashlightController mFlashlightController;
 
     public FlashlightTile(QSHost host) {
@@ -104,6 +98,9 @@
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
+        if (state.slash == null) {
+            state.slash = new SlashState();
+        }
         state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
         if (!mFlashlightController.isAvailable()) {
             Drawable icon = mHost.getContext().getDrawable(R.drawable.ic_signal_flashlight_enable)
@@ -123,8 +120,8 @@
         } else {
             state.value = mFlashlightController.isEnabled();
         }
-        final AnimationIcon icon = state.value ? mEnable : mDisable;
-        state.icon = icon;
+        state.icon = mIcon;
+        state.slash.isSlashed = !state.value;
         state.contentDescription = mContext.getString(R.string.quick_settings_flashlight_label);
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 40f2c4b..1c7c578 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -39,14 +39,7 @@
     static final Intent TETHER_SETTINGS = new Intent().setComponent(new ComponentName(
              "com.android.settings", "com.android.settings.TetherSettings"));
 
-    private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_hotspot_enable_animation,
-                    R.drawable.ic_hotspot_disable);
     private final Icon mEnabledStatic = ResourceIcon.get(R.drawable.ic_hotspot_disable);
-    private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_hotspot_disable_animation,
-                    R.drawable.ic_hotspot_enable);
-    private final Icon mDisableNoAnimation = ResourceIcon.get(R.drawable.ic_hotspot_enable);
     private final Icon mUnavailable = ResourceIcon.get(R.drawable.ic_hotspot_unavailable);
 
     private final HotspotController mController;
@@ -116,6 +109,9 @@
 
     @Override
     protected void handleUpdateState(AirplaneBooleanState state, Object arg) {
+        if (state.slash == null) {
+            state.slash = new SlashState();
+        }
         state.label = mContext.getString(R.string.quick_settings_hotspot_label);
 
         checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_CONFIG_TETHERING);
@@ -124,18 +120,12 @@
         } else {
             state.value = mController.isHotspotEnabled();
         }
-        state.icon = !state.value ? mDisable
-                : state.isTransient ? mEnabledStatic
-                : mEnable;
-        boolean wasAirplane = state.isAirplaneMode;
+        state.icon = mEnabledStatic;
         state.isAirplaneMode = mAirplaneMode.getValue() != 0;
         state.isTransient = mController.isHotspotTransient();
+        state.slash.isSlashed = !state.value && !state.isTransient;
         if (state.isTransient) {
             state.icon = ResourceIcon.get(R.drawable.ic_hotspot_transient_animation);
-        } else if (state.isAirplaneMode) {
-            state.icon = mUnavailable;
-        } else if (wasAirplane) {
-            state.icon = mDisableNoAnimation;
         }
         state.expandedAccessibilityClassName = Switch.class.getName();
         state.contentDescription = state.label;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 6522e10..96f2f68 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -25,6 +25,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
+import com.android.systemui.R.drawable;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -36,12 +37,7 @@
 /** Quick settings tile: Location **/
 public class LocationTile extends QSTileImpl<BooleanState> {
 
-    private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_signal_location_enable_animation,
-                    R.drawable.ic_signal_location_disable);
-    private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_signal_location_disable_animation,
-                    R.drawable.ic_signal_location_enable);
+    private final Icon mIcon = ResourceIcon.get(drawable.ic_signal_location_disable);
 
     private final LocationController mController;
     private final KeyguardMonitor mKeyguard;
@@ -95,6 +91,9 @@
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
+        if (state.slash == null) {
+            state.slash = new SlashState();
+        }
         final boolean locationEnabled =  mController.isLocationEnabled();
 
         // Work around for bug 15916487: don't show location tile on top of lock screen. After the
@@ -102,13 +101,13 @@
         // state.visible = !(mKeyguard.isSecure() && mKeyguard.isShowing());
         state.value = locationEnabled;
         checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_SHARE_LOCATION);
+        state.icon = mIcon;
+        state.slash.isSlashed = !state.value;
         if (locationEnabled) {
-            state.icon = mEnable;
             state.label = mContext.getString(R.string.quick_settings_location_label);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_location_on);
         } else {
-            state.icon = mDisable;
             state.label = mContext.getString(R.string.quick_settings_location_label);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_location_off);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 1afce64..b346d40 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -150,6 +150,12 @@
             mDetailAdapter.setItemsVisible(cb.enabled);
             fireToggleStateChanged(cb.enabled);
         }
+        if (state.slash == null) {
+            state.slash = new SlashState();
+            state.slash.rotation = 8;
+        }
+        state.slash.isSlashed = false;
+        state.state = Tile.STATE_ACTIVE;
         state.dualTarget = true;
         state.value = cb.enabled;
         state.activityIn = cb.enabled && cb.activityIn;
@@ -160,6 +166,8 @@
             state.icon = ResourceIcon.get(R.drawable.ic_signal_wifi_transient_animation);
             state.label = r.getString(R.string.quick_settings_wifi_label);
         } else if (!state.value) {
+            state.slash.isSlashed = true;
+            state.state = Tile.STATE_INACTIVE;
             state.icon = ResourceIcon.get(R.drawable.ic_qs_wifi_disabled);
             state.label = r.getString(R.string.quick_settings_wifi_label);
         } else if (wifiConnected) {
@@ -184,7 +192,6 @@
         state.dualLabelContentDescription = r.getString(
                 R.string.accessibility_quick_settings_open_settings, getTileLabel());
         state.expandedAccessibilityClassName = Switch.class.getName();
-        state.state = Tile.STATE_ACTIVE;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index a9e1f61..f431517 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -158,7 +158,7 @@
         public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
         public void onActivityPinned(String packageName) { }
         public void onActivityUnpinned() { }
-        public void onPinnedActivityRestartAttempt() { }
+        public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
         public void onPinnedStackAnimationStarted() { }
         public void onPinnedStackAnimationEnded() { }
         public void onActivityForcedResizable(String packageName, int taskId, int reason) { }
@@ -223,10 +223,11 @@
         }
 
         @Override
-        public void onPinnedActivityRestartAttempt()
+        public void onPinnedActivityRestartAttempt(boolean clearedTask)
                 throws RemoteException{
             mHandler.removeMessages(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
-            mHandler.sendEmptyMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT);
+            mHandler.obtainMessage(H.ON_PINNED_ACTIVITY_RESTART_ATTEMPT, clearedTask ? 1 : 0, 0)
+                    .sendToTarget();
         }
 
         @Override
@@ -1294,7 +1295,8 @@
                     }
                     case ON_PINNED_ACTIVITY_RESTART_ATTEMPT: {
                         for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onPinnedActivityRestartAttempt();
+                            mTaskStackListeners.get(i).onPinnedActivityRestartAttempt(
+                                    msg.arg1 != 0);
                         }
                         break;
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 5817e92..36be49d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -279,6 +279,7 @@
                         }
 
                         MetricsLogger.action(mSv.getContext(), MetricsEvent.OVERVIEW_SCROLL);
+                        mLastY = mDownY = y;
                     }
                 }
                 if (mIsScrolling) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index e34987b..4b614ed 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -362,11 +362,17 @@
      * Cancels any current transform animations.
      */
     public void cancelTransformAnimation() {
+        cancelDimAnimationIfExists();
         Utilities.cancelAnimationWithoutCallbacks(mTransformAnimation);
-        Utilities.cancelAnimationWithoutCallbacks(mDimAnimator);
         Utilities.cancelAnimationWithoutCallbacks(mOutlineAnimator);
     }
 
+    private void cancelDimAnimationIfExists() {
+        if (mDimAnimator != null) {
+            mDimAnimator.cancel();
+        }
+    }
+
     /** Enables/disables handling touch on this task view. */
     public void setTouchEnabled(boolean enabled) {
         setOnClickListener(enabled ? this : null);
@@ -546,7 +552,7 @@
     @Override
     public void onStartLaunchTargetEnterAnimation(TaskViewTransform transform, int duration,
             boolean screenPinningEnabled, ReferenceCountedTrigger postAnimationTrigger) {
-        Utilities.cancelAnimationWithoutCallbacks(mDimAnimator);
+        cancelDimAnimationIfExists();
 
         // Dim the view after the app window transitions down into recents
         postAnimationTrigger.increment();
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index da56e62..90c65580 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -767,7 +767,7 @@
             mDockedStackMinimized = minimized;
         } else if (mDockedStackMinimized != minimized) {
             mIsInMinimizeInteraction = true;
-            if (minimized) {
+            if (minimized && (mCurrentAnimator == null || !mCurrentAnimator.isRunning())) {
                 mDividerPositionBeforeMinimized = getCurrentPosition();
             }
             mMinimizedSnapAlgorithm = null;
diff --git a/core/java/android/app/CompatibilityDisplayProperties.aidl b/packages/SystemUI/src/com/android/systemui/statusbar/Abortable.java
similarity index 75%
copy from core/java/android/app/CompatibilityDisplayProperties.aidl
copy to packages/SystemUI/src/com/android/systemui/statusbar/Abortable.java
index 626a63e..d5ec4f67 100644
--- a/core/java/android/app/CompatibilityDisplayProperties.aidl
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/Abortable.java
@@ -11,10 +11,14 @@
  * 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.
+ * limitations under the License
  */
 
-package android.app;
+package com.android.systemui.statusbar;
 
-/** @hide */
-parcelable CompatibilityDisplayProperties;
+/**
+ * An interface that allows aborting existing operations.
+ */
+public interface Abortable {
+    void abort();
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index d7eab97..b91561e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -891,7 +891,7 @@
      * @return the calculated background color
      */
     private int calculateBgColor(boolean withTint, boolean withOverRide) {
-        if (mDark) {
+        if (withTint && mDark) {
             return getContext().getColor(R.color.notification_material_background_dark_color);
         }
         if (withOverRide && mOverrideTint != NO_COLOR) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 072373b..f22dc058 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -86,6 +86,11 @@
     private static final int COLORED_DIVIDER_ALPHA = 0x7B;
     private static final int MENU_VIEW_INDEX = 0;
 
+    public interface LayoutListener {
+        public void onLayout();
+    }
+
+    private LayoutListener mLayoutListener;
     private final NotificationInflater mNotificationInflater;
     private int mIconTransformContentShift;
     private int mIconTransformContentShiftNoIcon;
@@ -357,7 +362,8 @@
                 NotificationColorUtil.getInstance(mContext));
         int color = StatusBarIconView.NO_COLOR;
         if (colorize) {
-            color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded());
+            color = mEntry.getContrastedColor(mContext, mIsLowPriority && !isExpanded(),
+                    getBackgroundColorWithoutTint());
         }
         expandedIcon.setStaticDrawableColor(color);
     }
@@ -870,7 +876,8 @@
 
     private void updateNotificationColor() {
         mNotificationColor = NotificationColorUtil.resolveContrastColor(mContext,
-                getStatusBarNotification().getNotification().color);
+                getStatusBarNotification().getNotification().color,
+                getBackgroundColorWithoutTint());
     }
 
     public HybridNotificationView getSingleLineView() {
@@ -1608,6 +1615,14 @@
         mIsSystemChildExpanded = expanded;
     }
 
+    public void setLayoutListener(LayoutListener listener) {
+        mLayoutListener = listener;
+    }
+
+    public void removeListener() {
+        mLayoutListener = null;
+    }
+
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
@@ -1616,6 +1631,9 @@
             mMenuRow.onHeightUpdate();
         }
         updateContentShiftHeight();
+        if (mLayoutListener != null) {
+            mLayoutListener.onLayout();
+        }
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 540c391..f8bad05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -33,7 +33,6 @@
 import android.service.notification.SnoozeCriterion;
 import android.service.notification.StatusBarNotification;
 import android.util.ArrayMap;
-import android.util.ArraySet;
 import android.view.View;
 import android.widget.ImageView;
 import android.widget.RemoteViews;
@@ -43,7 +42,6 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.statusbar.notification.InflationException;
-import com.android.systemui.statusbar.notification.NotificationInflater;
 import com.android.systemui.statusbar.phone.NotificationGroupManager;
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
@@ -86,7 +84,7 @@
         public List<SnoozeCriterion> snoozeCriteria;
         private int mCachedContrastColor = COLOR_INVALID;
         private int mCachedContrastColorIsFor = COLOR_INVALID;
-        private ArraySet<AsyncTask> mRunningTasks = new ArraySet();
+        private Abortable mRunningTask = null;
 
         public Entry(StatusBarNotification n) {
             this.key = n.getKey();
@@ -203,13 +201,15 @@
             }
         }
 
-        public int getContrastedColor(Context context, boolean ambient) {
-            int rawColor = ambient ? Notification.COLOR_DEFAULT :
+        public int getContrastedColor(Context context, boolean isLowPriority,
+                int backgroundColor) {
+            int rawColor = isLowPriority ? Notification.COLOR_DEFAULT :
                     notification.getNotification().color;
             if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
                 return mCachedContrastColor;
             }
-            final int contrasted = NotificationColorUtil.resolveContrastColor(context, rawColor);
+            final int contrasted = NotificationColorUtil.resolveContrastColor(context, rawColor,
+                    backgroundColor);
             mCachedContrastColorIsFor = rawColor;
             mCachedContrastColor = contrasted;
             return mCachedContrastColor;
@@ -218,24 +218,26 @@
         /**
          * Abort all existing inflation tasks
          */
-        public void abortInflation() {
-            for (AsyncTask task : mRunningTasks) {
-                task.cancel(true /* mayInterruptIfRunning */);
+        public void abortTask() {
+            if (mRunningTask != null) {
+                mRunningTask.abort();
+                mRunningTask = null;
             }
-            mRunningTasks.clear();
         }
 
-        public void addInflationTask(AsyncTask asyncInflationTask) {
-            mRunningTasks.add(asyncInflationTask);
+        public void setInflationTask(Abortable abortableTask) {
+            // abort any existing inflation
+            abortTask();
+            mRunningTask = abortableTask;
         }
 
-        public void onInflationTaskFinished(AsyncTask asyncInflationTask) {
-            mRunningTasks.remove(asyncInflationTask);
+        public void onInflationTaskFinished() {
+           mRunningTask = null;
         }
 
         @VisibleForTesting
-        public ArraySet<AsyncTask> getRunningTasks() {
-            return mRunningTasks;
+        public Abortable getRunningTask() {
+            return mRunningTask;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
index 8d3bff2..d4b8920 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMenuRow.java
@@ -35,6 +35,7 @@
 import android.content.res.Resources;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.Looper;
 import android.util.Log;
 import android.service.notification.StatusBarNotification;
 import android.view.LayoutInflater;
@@ -44,7 +45,8 @@
 import android.widget.FrameLayout;
 import android.widget.FrameLayout.LayoutParams;
 
-public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnClickListener {
+public class NotificationMenuRow implements NotificationMenuRowPlugin, View.OnClickListener,
+        ExpandableNotificationRow.LayoutListener {
 
     private static final boolean DEBUG = false;
     private static final String TAG = "swipe";
@@ -107,7 +109,7 @@
         mHorizSpaceForIcon = res.getDimensionPixelSize(R.dimen.notification_menu_icon_size);
         mVertSpaceForIcons = res.getDimensionPixelSize(R.dimen.notification_min_height);
         mIconPadding = res.getDimensionPixelSize(R.dimen.notification_menu_icon_padding);
-        mHandler = new Handler();
+        mHandler = new Handler(Looper.getMainLooper());
         mMenuItems = new ArrayList<>();
         mSnoozeItem = createSnoozeItem(context);
         mInfoItem = createInfoItem(context);
@@ -167,13 +169,14 @@
 
     @Override
     public void onConfigurationChanged() {
-        mParent.post(new Runnable() {
-            @Override
-            public void run() {
-                mIconsPlaced = false; // Force icons to be re-placed
-                setMenuLocation();
-            }
-        });
+        mParent.setLayoutListener(this);
+    }
+
+    @Override
+    public void onLayout() {
+        mIconsPlaced = false; // Force icons to be re-placed
+        setMenuLocation();
+        mParent.removeListener();
     }
 
     private void createMenuViews() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index d9ac4d5..8588668 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -167,6 +167,10 @@
     }
 
     public void setColors(@NonNull ColorExtractor.GradientColors colors) {
+        setColors(colors, false);
+    }
+
+    public void setColors(@NonNull ColorExtractor.GradientColors colors, boolean animated) {
         if (colors == null) {
             throw new IllegalArgumentException("Colors cannot be null");
         }
@@ -174,7 +178,7 @@
             return;
         }
         mColors.set(colors);
-        updateColorWithTint();
+        updateColorWithTint(animated);
     }
 
     @VisibleForTesting
@@ -183,14 +187,18 @@
     }
 
     public void setTint(int color) {
+        setTint(color, false);
+    }
+
+    public void setTint(int color, boolean animated) {
         if (mTintColor == color) {
             return;
         }
         mTintColor = color;
-        updateColorWithTint();
+        updateColorWithTint(animated);
     }
 
-    private void updateColorWithTint() {
+    private void updateColorWithTint(boolean animated) {
         if (mDrawable instanceof GradientDrawable) {
             // Optimization to blend colors and avoid a color filter
             GradientDrawable drawable = (GradientDrawable) mDrawable;
@@ -199,7 +207,7 @@
                     tintAmount);
             int secondaryTinted = ColorUtils.blendARGB(mColors.getSecondaryColor(), mTintColor,
                     tintAmount);
-            drawable.setColors(mainTinted, secondaryTinted, false);
+            drawable.setColors(mainTinted, secondaryTinted, animated);
         } else {
             if (mColorFilter == null) {
                 mColorFilter = new PorterDuffColorFilter(mTintColor, PorterDuff.Mode.SRC_OVER);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java
index 82910b8..454edbb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ImageGradientColorizer.java
@@ -34,7 +34,7 @@
  * A utility class to colorize bitmaps with a color gradient and a special blending mode
  */
 public class ImageGradientColorizer {
-    public Bitmap colorize(Drawable drawable, int backgroundColor) {
+    public Bitmap colorize(Drawable drawable, int backgroundColor, boolean isRtl) {
         int width = drawable.getIntrinsicWidth();
         int height = drawable.getIntrinsicHeight();
         int size = Math.min(width, height);
@@ -70,8 +70,6 @@
                 0, 0, 0, 1, 0,
         });
 
-        drawable.setColorFilter(new ColorMatrixColorFilter(m));
-        drawable.draw(canvas);
         Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
         LinearGradient linearGradient =  new LinearGradient(0, 0, size, 0,
                 new int[] {0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
@@ -81,16 +79,27 @@
         Canvas fadeInCanvas = new Canvas(fadeIn);
         drawable.clearColorFilter();
         drawable.draw(fadeInCanvas);
+
+        if (isRtl) {
+            // Let's flip the gradient
+            fadeInCanvas.translate(size, 0);
+            fadeInCanvas.scale(-1, 1);
+        }
         paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
         fadeInCanvas.drawPaint(paint);
+
+        Paint coloredPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        coloredPaint.setColorFilter(new ColorMatrixColorFilter(m));
+        coloredPaint.setAlpha((int) (0.5f * 255));
+        canvas.drawBitmap(fadeIn, 0, 0, coloredPaint);
+
+        linearGradient =  new LinearGradient(0, 0, size, 0,
+                new int[] {0, Color.argb(0.5f, 1, 1, 1), Color.BLACK},
+                new float[] {0.0f, 0.6f, 1.0f}, Shader.TileMode.CLAMP);
+        paint.setShader(linearGradient);
+        fadeInCanvas.drawPaint(paint);
         canvas.drawBitmap(fadeIn, 0, 0, null);
 
-        linearGradient = new LinearGradient(0, 0, size, 0,
-                new int[] {backgroundColor, Color.argb(0.5f, tr, tg, tb), 0},
-                new float[] {0.0f, 0.6f, 1.0f}, Shader.TileMode.CLAMP);
-        paint.setShader(linearGradient);
-        paint.setXfermode(null);
-        canvas.drawPaint(paint);
         return newBitmap;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
index cef225b..52c053f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -25,6 +25,7 @@
 import android.graphics.drawable.Icon;
 import android.support.v4.graphics.ColorUtils;
 import android.support.v7.graphics.Palette;
+import android.util.LayoutDirection;
 
 import com.android.systemui.R;
 
@@ -187,7 +188,9 @@
                         : R.color.notification_material_background_color;
                 backgroundColor = mContext.getColor(id);
             }
-            Bitmap colorized = mColorizer.colorize(drawable, backgroundColor);
+            Bitmap colorized = mColorizer.colorize(drawable, backgroundColor,
+                    mContext.getResources().getConfiguration().getLayoutDirection() ==
+                            LayoutDirection.RTL);
             builder.setLargeIcon(Icon.createWithBitmap(colorized));
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
index 7cfc767..f1c26cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInflater.java
@@ -16,19 +16,26 @@
 
 package com.android.systemui.statusbar.notification;
 
+import android.annotation.Nullable;
 import android.app.Notification;
 import android.content.Context;
 import android.os.AsyncTask;
+import android.os.CancellationSignal;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
 import android.view.View;
 import android.widget.RemoteViews;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.R;
+import com.android.systemui.statusbar.Abortable;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.NotificationContentView;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.phone.StatusBar;
+import com.android.systemui.util.Assert;
+
+import java.util.HashMap;
 
 /**
  * A utility that inflates the right kind of contentView based on the state
@@ -116,126 +123,303 @@
     @VisibleForTesting
     void inflateNotificationViews(int reInflateFlags) {
         StatusBarNotification sbn = mRow.getEntry().notification;
-        new AsyncInflationTask(mRow.getContext(), sbn, reInflateFlags).execute();
+        new AsyncInflationTask(sbn, reInflateFlags, mRow, mIsLowPriority,
+                mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
+                mCallback, mRemoteViewClickHandler).execute();
     }
 
     @VisibleForTesting
-    void inflateNotificationViews(int reInflateFlags,
+    InflationProgress inflateNotificationViews(int reInflateFlags,
             Notification.Builder builder, Context packageContext) {
-        NotificationData.Entry entry = mRow.getEntry();
-        NotificationContentView privateLayout = mRow.getPrivateLayout();
-        NotificationContentView publicLayout = mRow.getPublicLayout();
+        InflationProgress result = createRemoteViews(reInflateFlags, builder, mIsLowPriority,
+                mIsChildInGroup, mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight,
+                mRedactAmbient, packageContext);
+        apply(result, reInflateFlags, mRow, mRedactAmbient, mRemoteViewClickHandler, null);
+        return result;
+    }
 
-        boolean isLowPriority = mIsLowPriority && !mIsChildInGroup;
+    private static InflationProgress createRemoteViews(int reInflateFlags,
+            Notification.Builder builder, boolean isLowPriority, boolean isChildInGroup,
+            boolean usesIncreasedHeight, boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
+            Context packageContext) {
+        InflationProgress result = new InflationProgress();
+        isLowPriority = isLowPriority && !isChildInGroup;
         if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
-            final RemoteViews newContentView = createContentView(builder,
-                    isLowPriority, mUsesIncreasedHeight);
-            if (!compareRemoteViews(newContentView,
-                    entry.cachedContentView)) {
-                View contentViewLocal = newContentView.apply(
-                        packageContext,
-                        privateLayout,
-                        mRemoteViewClickHandler);
-                contentViewLocal.setIsRootNamespace(true);
-                privateLayout.setContractedChild(contentViewLocal);
-            } else {
-                newContentView.reapply(packageContext,
-                        privateLayout.getContractedChild(),
-                        mRemoteViewClickHandler);
-            }
-            entry.cachedContentView = newContentView;
+            result.newContentView = createContentView(builder, isLowPriority, usesIncreasedHeight);
         }
 
         if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
-            final RemoteViews newBigContentView = createBigContentView(
-                    builder, isLowPriority);
-            if (newBigContentView != null) {
-                if (!compareRemoteViews(newBigContentView, entry.cachedBigContentView)) {
-                    View bigContentViewLocal = newBigContentView.apply(
-                            packageContext,
-                            privateLayout,
-                            mRemoteViewClickHandler);
-                    bigContentViewLocal.setIsRootNamespace(true);
-                    privateLayout.setExpandedChild(bigContentViewLocal);
-                } else {
-                    newBigContentView.reapply(packageContext,
-                            privateLayout.getExpandedChild(),
-                            mRemoteViewClickHandler);
-                }
-            } else if (entry.cachedBigContentView != null) {
-                privateLayout.setExpandedChild(null);
-            }
-            entry.cachedBigContentView = newBigContentView;
-            mRow.setExpandable(newBigContentView != null);
+            result.newExpandedView = createExpandedView(builder, isLowPriority);
         }
 
         if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
-            final RemoteViews newHeadsUpContentView =
-                    builder.createHeadsUpContentView(mUsesIncreasedHeadsUpHeight);
-            if (newHeadsUpContentView != null) {
-                if (!compareRemoteViews(newHeadsUpContentView,
-                        entry.cachedHeadsUpContentView)) {
-                    View headsUpContentViewLocal = newHeadsUpContentView.apply(
-                            packageContext,
-                            privateLayout,
-                            mRemoteViewClickHandler);
-                    headsUpContentViewLocal.setIsRootNamespace(true);
-                    privateLayout.setHeadsUpChild(headsUpContentViewLocal);
-                } else {
-                    newHeadsUpContentView.reapply(packageContext,
-                            privateLayout.getHeadsUpChild(),
-                            mRemoteViewClickHandler);
-                }
-            } else if (entry.cachedHeadsUpContentView != null) {
-                privateLayout.setHeadsUpChild(null);
-            }
-            entry.cachedHeadsUpContentView = newHeadsUpContentView;
+            result.newHeadsUpView = builder.createHeadsUpContentView(usesIncreasedHeadsUpHeight);
         }
 
         if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
-            final RemoteViews newPublicNotification
-                    = builder.makePublicContentView();
-            if (!compareRemoteViews(newPublicNotification, entry.cachedPublicContentView)) {
-                View publicContentView = newPublicNotification.apply(
-                        packageContext,
-                        publicLayout,
-                        mRemoteViewClickHandler);
-                publicContentView.setIsRootNamespace(true);
-                publicLayout.setContractedChild(publicContentView);
-            } else {
-                newPublicNotification.reapply(packageContext,
-                        publicLayout.getContractedChild(),
-                        mRemoteViewClickHandler);
-            }
-            entry.cachedPublicContentView = newPublicNotification;
+            result.newPublicView = builder.makePublicContentView();
         }
 
         if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
-            final RemoteViews newAmbientNotification = mRedactAmbient
-                    ? builder.makePublicAmbientNotification()
+            result.newAmbientView = redactAmbient ? builder.makePublicAmbientNotification()
                     : builder.makeAmbientNotification();
-            NotificationContentView newParent = mRedactAmbient ? publicLayout : privateLayout;
-            NotificationContentView otherParent = !mRedactAmbient ? publicLayout : privateLayout;
+        }
+        result.packageContext = packageContext;
+        return result;
+    }
 
-            if (newParent.getAmbientChild() == null ||
-                    !compareRemoteViews(newAmbientNotification, entry.cachedAmbientContentView)) {
-                View ambientContentView = newAmbientNotification.apply(
-                        packageContext,
-                        newParent,
-                        mRemoteViewClickHandler);
-                ambientContentView.setIsRootNamespace(true);
-                newParent.setAmbientChild(ambientContentView);
-                otherParent.setAmbientChild(null);
-            } else {
-                newAmbientNotification.reapply(packageContext,
-                        newParent.getAmbientChild(),
-                        mRemoteViewClickHandler);
+    public static CancellationSignal apply(InflationProgress result, int reInflateFlags,
+            ExpandableNotificationRow row, boolean redactAmbient,
+            RemoteViews.OnClickHandler remoteViewClickHandler,
+            @Nullable InflationCallback callback) {
+        NotificationData.Entry entry = row.getEntry();
+        NotificationContentView privateLayout = row.getPrivateLayout();
+        NotificationContentView publicLayout = row.getPublicLayout();
+        final HashMap<Integer, CancellationSignal> runningInflations = new HashMap<>();
+
+        int flag = FLAG_REINFLATE_CONTENT_VIEW;
+        if ((reInflateFlags & flag) != 0) {
+            boolean isNewView = !compareRemoteViews(result.newContentView, entry.cachedContentView);
+            ApplyCallback applyCallback = new ApplyCallback() {
+                @Override
+                public void setResultView(View v) {
+                    result.inflatedContentView = v;
+                }
+
+                @Override
+                public RemoteViews getRemoteView() {
+                    return result.newContentView;
+                }
+            };
+            applyRemoteView(result, reInflateFlags, flag, row, redactAmbient,
+                    isNewView, remoteViewClickHandler, callback, entry, privateLayout,
+                    privateLayout.getContractedChild(),
+                    runningInflations, applyCallback);
+        }
+
+        flag = FLAG_REINFLATE_EXPANDED_VIEW;
+        if ((reInflateFlags & flag) != 0) {
+            if (result.newExpandedView != null) {
+                boolean isNewView = !compareRemoteViews(result.newExpandedView,
+                        entry.cachedBigContentView);
+                ApplyCallback applyCallback = new ApplyCallback() {
+                    @Override
+                    public void setResultView(View v) {
+                        result.inflatedExpandedView = v;
+                    }
+
+                    @Override
+                    public RemoteViews getRemoteView() {
+                        return result.newExpandedView;
+                    }
+                };
+                applyRemoteView(result, reInflateFlags, flag, row,
+                        redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+                        privateLayout, privateLayout.getExpandedChild(), runningInflations,
+                        applyCallback);
             }
-            entry.cachedAmbientContentView = newAmbientNotification;
+        }
+
+        flag = FLAG_REINFLATE_HEADS_UP_VIEW;
+        if ((reInflateFlags & flag) != 0) {
+            if (result.newHeadsUpView != null) {
+                boolean isNewView = !compareRemoteViews(result.newHeadsUpView,
+                        entry.cachedHeadsUpContentView);
+                ApplyCallback applyCallback = new ApplyCallback() {
+                    @Override
+                    public void setResultView(View v) {
+                        result.inflatedHeadsUpView = v;
+                    }
+
+                    @Override
+                    public RemoteViews getRemoteView() {
+                        return result.newHeadsUpView;
+                    }
+                };
+                applyRemoteView(result, reInflateFlags, flag, row,
+                        redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+                        privateLayout, privateLayout.getHeadsUpChild(), runningInflations,
+                        applyCallback);
+            }
+        }
+
+        flag = FLAG_REINFLATE_PUBLIC_VIEW;
+        if ((reInflateFlags & flag) != 0) {
+            boolean isNewView = !compareRemoteViews(result.newPublicView,
+                    entry.cachedPublicContentView);
+            ApplyCallback applyCallback = new ApplyCallback() {
+                @Override
+                public void setResultView(View v) {
+                    result.inflatedPublicView = v;
+                }
+
+                @Override
+                public RemoteViews getRemoteView() {
+                    return result.newPublicView;
+                }
+            };
+            applyRemoteView(result, reInflateFlags, flag, row,
+                    redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+                    publicLayout, publicLayout.getContractedChild(), runningInflations,
+                    applyCallback);
+        }
+
+        flag = FLAG_REINFLATE_AMBIENT_VIEW;
+        if ((reInflateFlags & flag) != 0) {
+            NotificationContentView newParent = redactAmbient ? publicLayout : privateLayout;
+            boolean isNewView = !canReapplyAmbient(row, redactAmbient) ||
+                    !compareRemoteViews(result.newAmbientView, entry.cachedAmbientContentView);
+            ApplyCallback applyCallback = new ApplyCallback() {
+                @Override
+                public void setResultView(View v) {
+                    result.inflatedAmbientView = v;
+                }
+
+                @Override
+                public RemoteViews getRemoteView() {
+                    return result.newAmbientView;
+                }
+            };
+            applyRemoteView(result, reInflateFlags, flag, row,
+                    redactAmbient, isNewView, remoteViewClickHandler, callback, entry,
+                    newParent, newParent.getAmbientChild(), runningInflations,
+                    applyCallback);
+        }
+
+        // Let's try to finish, maybe nobody is even inflating anything
+        finishIfDone(result, reInflateFlags, runningInflations, callback, row,
+                redactAmbient);
+        CancellationSignal cancellationSignal = new CancellationSignal();
+        cancellationSignal.setOnCancelListener(
+                () -> runningInflations.values().forEach(CancellationSignal::cancel));
+        return cancellationSignal;
+    }
+
+    private static void applyRemoteView(final InflationProgress result,
+            final int reInflateFlags, int inflationId,
+            final ExpandableNotificationRow row,
+            final boolean redactAmbient, boolean isNewView,
+            RemoteViews.OnClickHandler remoteViewClickHandler,
+            @Nullable final InflationCallback callback, NotificationData.Entry entry,
+            NotificationContentView parentLayout, View existingView,
+            final HashMap<Integer, CancellationSignal> runningInflations,
+            ApplyCallback applyCallback) {
+        RemoteViews.OnViewAppliedListener listener
+                = new RemoteViews.OnViewAppliedListener() {
+
+            @Override
+            public void onViewApplied(View v) {
+                if (isNewView) {
+                    v.setIsRootNamespace(true);
+                    applyCallback.setResultView(v);
+                }
+                runningInflations.remove(inflationId);
+                finishIfDone(result, reInflateFlags, runningInflations, callback, row,
+                        redactAmbient);
+            }
+
+            @Override
+            public void onError(Exception e) {
+                runningInflations.remove(inflationId);
+                handleInflationError(runningInflations, e, entry.notification, callback);
+            }
+        };
+        CancellationSignal cancellationSignal;
+        RemoteViews newContentView = applyCallback.getRemoteView();
+        if (isNewView) {
+            cancellationSignal = newContentView.applyAsync(
+                    result.packageContext,
+                    parentLayout,
+                    null /* executor */,
+                    listener,
+                    remoteViewClickHandler);
+        } else {
+            cancellationSignal = newContentView.reapplyAsync(
+                    result.packageContext,
+                    existingView,
+                    null /* executor */,
+                    listener,
+                    remoteViewClickHandler);
+        }
+        runningInflations.put(inflationId, cancellationSignal);
+    }
+
+    private static void handleInflationError(HashMap<Integer, CancellationSignal> runningInflations,
+            Exception e, StatusBarNotification notification, @Nullable InflationCallback callback) {
+        Assert.isMainThread();
+        runningInflations.values().forEach(CancellationSignal::cancel);
+        if (callback != null) {
+            callback.handleInflationException(notification, e);
         }
     }
 
-    private RemoteViews createBigContentView(Notification.Builder builder,
+    /**
+     * Finish the inflation of the views
+     *
+     * @return true if the inflation was finished
+     */
+    private static boolean finishIfDone(InflationProgress result, int reInflateFlags,
+            HashMap<Integer, CancellationSignal> runningInflations,
+            @Nullable InflationCallback endListener, ExpandableNotificationRow row,
+            boolean redactAmbient) {
+        Assert.isMainThread();
+        NotificationData.Entry entry = row.getEntry();
+        NotificationContentView privateLayout = row.getPrivateLayout();
+        NotificationContentView publicLayout = row.getPublicLayout();
+        if (runningInflations.isEmpty()) {
+            if ((reInflateFlags & FLAG_REINFLATE_CONTENT_VIEW) != 0) {
+                if (result.inflatedContentView != null) {
+                    privateLayout.setContractedChild(result.inflatedContentView);
+                }
+                entry.cachedContentView = result.newContentView;
+            }
+
+            if ((reInflateFlags & FLAG_REINFLATE_EXPANDED_VIEW) != 0) {
+                if (result.inflatedExpandedView != null) {
+                    privateLayout.setExpandedChild(result.inflatedExpandedView);
+                } else if (result.newExpandedView == null) {
+                    privateLayout.setExpandedChild(null);
+                }
+                entry.cachedBigContentView = result.newExpandedView;
+                row.setExpandable(result.newExpandedView != null);
+            }
+
+            if ((reInflateFlags & FLAG_REINFLATE_HEADS_UP_VIEW) != 0) {
+                if (result.inflatedHeadsUpView != null) {
+                    privateLayout.setHeadsUpChild(result.inflatedHeadsUpView);
+                } else if (result.newHeadsUpView == null) {
+                    privateLayout.setHeadsUpChild(null);
+                }
+                entry.cachedHeadsUpContentView = result.newHeadsUpView;
+            }
+
+            if ((reInflateFlags & FLAG_REINFLATE_PUBLIC_VIEW) != 0) {
+                if (result.inflatedPublicView != null) {
+                    publicLayout.setContractedChild(result.inflatedPublicView);
+                }
+                entry.cachedPublicContentView = result.newPublicView;
+            }
+
+            if ((reInflateFlags & FLAG_REINFLATE_AMBIENT_VIEW) != 0) {
+                if (result.inflatedAmbientView != null) {
+                    NotificationContentView newParent = redactAmbient
+                            ? publicLayout : privateLayout;
+                    NotificationContentView otherParent = !redactAmbient
+                            ? publicLayout : privateLayout;
+                    newParent.setAmbientChild(result.inflatedAmbientView);
+                    otherParent.setAmbientChild(null);
+                }
+                entry.cachedAmbientContentView = result.newAmbientView;
+            }
+            if (endListener != null) {
+                endListener.onAsyncInflationFinished(row.getEntry());
+            }
+            return true;
+        }
+        return false;
+    }
+
+    private static RemoteViews createExpandedView(Notification.Builder builder,
             boolean isLowPriority) {
         RemoteViews bigContentView = builder.createBigContentView();
         if (bigContentView != null) {
@@ -249,7 +433,7 @@
         return null;
     }
 
-    private RemoteViews createContentView(Notification.Builder builder,
+    private static RemoteViews createContentView(Notification.Builder builder,
             boolean isLowPriority, boolean useLarge) {
         if (isLowPriority) {
             return builder.makeLowPriorityContentView(false /* useRegularSubtext */);
@@ -258,7 +442,7 @@
     }
 
     // Returns true if the RemoteViews are the same.
-    private boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
+    private static boolean compareRemoteViews(final RemoteViews a, final RemoteViews b) {
         return (a == null && b == null) ||
                 (a != null && b != null
                         && b.getPackage() != null
@@ -272,7 +456,7 @@
     }
 
     public interface InflationCallback {
-        void handleInflationException(StatusBarNotification notification, InflationException e);
+        void handleInflationException(StatusBarNotification notification, Exception e);
         void onAsyncInflationFinished(NotificationData.Entry entry);
     }
 
@@ -286,37 +470,73 @@
         inflateNotificationViews();
     }
 
-    private class AsyncInflationTask extends AsyncTask<Void, Void, Notification.Builder> {
+    private static boolean canReapplyAmbient(ExpandableNotificationRow row, boolean redactAmbient) {
+        NotificationContentView ambientView = redactAmbient ? row.getPublicLayout()
+                : row.getPrivateLayout();            ;
+        return ambientView.getAmbientChild() != null;
+    }
+
+    public static class AsyncInflationTask extends AsyncTask<Void, Void, InflationProgress>
+            implements InflationCallback, Abortable {
 
         private final StatusBarNotification mSbn;
         private final Context mContext;
         private final int mReInflateFlags;
-        private Context mPackageContext = null;
+        private final boolean mIsLowPriority;
+        private final boolean mIsChildInGroup;
+        private final boolean mUsesIncreasedHeight;
+        private final InflationCallback mCallback;
+        private final boolean mUsesIncreasedHeadsUpHeight;
+        private final boolean mRedactAmbient;
+        private ExpandableNotificationRow mRow;
         private Exception mError;
+        private RemoteViews.OnClickHandler mRemoteViewClickHandler;
+        private CancellationSignal mCancellationSignal;
 
-        private AsyncInflationTask(Context context, StatusBarNotification notification,
-                int reInflateFlags) {
+        private AsyncInflationTask(StatusBarNotification notification,
+                int reInflateFlags, ExpandableNotificationRow row, boolean isLowPriority,
+                boolean isChildInGroup, boolean usesIncreasedHeight,
+                boolean usesIncreasedHeadsUpHeight, boolean redactAmbient,
+                InflationCallback callback,
+                RemoteViews.OnClickHandler remoteViewClickHandler) {
+            mRow = row;
+            NotificationData.Entry entry = row.getEntry();
+            entry.setInflationTask(this);
             mSbn = notification;
-            mContext = context;
             mReInflateFlags = reInflateFlags;
-            mRow.getEntry().addInflationTask(this);
+            mContext = mRow.getContext();
+            mIsLowPriority = isLowPriority;
+            mIsChildInGroup = isChildInGroup;
+            mUsesIncreasedHeight = usesIncreasedHeight;
+            mUsesIncreasedHeadsUpHeight = usesIncreasedHeadsUpHeight;
+            mRedactAmbient = redactAmbient;
+            mRemoteViewClickHandler = remoteViewClickHandler;
+            mCallback = callback;
         }
 
         @Override
-        protected Notification.Builder doInBackground(Void... params) {
+        protected InflationProgress doInBackground(Void... params) {
             try {
                 final Notification.Builder recoveredBuilder
                         = Notification.Builder.recoverBuilder(mContext,
                         mSbn.getNotification());
-                mPackageContext = mSbn.getPackageContext(mContext);
+                Context packageContext = mSbn.getPackageContext(mContext);
                 Notification notification = mSbn.getNotification();
+                if (mIsLowPriority) {
+                    int backgroundColor = mContext.getColor(
+                            R.color.notification_material_background_low_priority_color);
+                    recoveredBuilder.setBackgroundColorHint(backgroundColor);
+                }
                 if (notification.isMediaNotification()) {
                     MediaNotificationProcessor processor = new MediaNotificationProcessor(mContext,
-                            mPackageContext);
+                            packageContext);
                     processor.setIsLowPriority(mIsLowPriority);
                     processor.processNotification(notification, recoveredBuilder);
                 }
-                return recoveredBuilder;
+                return createRemoteViews(mReInflateFlags,
+                        recoveredBuilder, mIsLowPriority, mIsChildInGroup,
+                        mUsesIncreasedHeight, mUsesIncreasedHeadsUpHeight, mRedactAmbient,
+                        packageContext);
             } catch (Exception e) {
                 mError = e;
                 return null;
@@ -324,34 +544,64 @@
         }
 
         @Override
-        protected void onPostExecute(Notification.Builder builder) {
-            mRow.getEntry().onInflationTaskFinished(this);
+        protected void onPostExecute(InflationProgress result) {
             if (mError == null) {
-                finishInflation(mReInflateFlags, builder, mPackageContext);
+                mCancellationSignal = apply(result, mReInflateFlags, mRow, mRedactAmbient,
+                        mRemoteViewClickHandler, this);
             } else {
                 handleError(mError);
             }
         }
-    }
 
-    private void finishInflation(int reinflationFlags, Notification.Builder builder,
-            Context context) {
-        try {
-            inflateNotificationViews(reinflationFlags, builder, context);
-        } catch (RuntimeException e){
-            handleError(e);
-            return;
+        private void handleError(Exception e) {
+            mRow.getEntry().onInflationTaskFinished();
+            StatusBarNotification sbn = mRow.getStatusBarNotification();
+            final String ident = sbn.getPackageName() + "/0x"
+                    + Integer.toHexString(sbn.getId());
+            Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
+            mCallback.handleInflationException(sbn,
+                    new InflationException("Couldn't inflate contentViews" + e));
         }
-        mRow.onNotificationUpdated();
-        mCallback.onAsyncInflationFinished(mRow.getEntry());
+
+        @Override
+        public void abort() {
+            cancel(true /* mayInterruptIfRunning */);
+            if (mCancellationSignal != null) {
+                mCancellationSignal.cancel();
+            }
+        }
+
+        @Override
+        public void handleInflationException(StatusBarNotification notification, Exception e) {
+            handleError(e);
+        }
+
+        @Override
+        public void onAsyncInflationFinished(NotificationData.Entry entry) {
+            mRow.getEntry().onInflationTaskFinished();
+            mRow.onNotificationUpdated();
+            mCallback.onAsyncInflationFinished(mRow.getEntry());
+        }
     }
 
-    private void handleError(Exception e) {
-        StatusBarNotification sbn = mRow.getStatusBarNotification();
-        final String ident = sbn.getPackageName() + "/0x"
-                + Integer.toHexString(sbn.getId());
-        Log.e(StatusBar.TAG, "couldn't inflate view for notification " + ident, e);
-        mCallback.handleInflationException(sbn,
-                new InflationException("Couldn't inflate contentViews" + e));
+    private static class InflationProgress {
+        private RemoteViews newContentView;
+        private RemoteViews newHeadsUpView;
+        private RemoteViews newExpandedView;
+        private RemoteViews newAmbientView;
+        private RemoteViews newPublicView;
+
+        private Context packageContext;
+
+        private View inflatedContentView;
+        private View inflatedHeadsUpView;
+        private View inflatedExpandedView;
+        private View inflatedAmbientView;
+        private View inflatedPublicView;
+    }
+
+    private abstract static class ApplyCallback {
+        public abstract void setResultView(View v);
+        public abstract RemoteViews getRemoteView();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/RowInflaterTask.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RowInflaterTask.java
new file mode 100644
index 0000000..1bfc0cc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/RowInflaterTask.java
@@ -0,0 +1,65 @@
+/*
+ * 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.statusbar.notification;
+
+import android.content.Context;
+import android.support.v4.view.AsyncLayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.Abortable;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+import com.android.systemui.statusbar.NotificationData;
+
+/**
+ * An inflater task that asynchronously inflates a ExpandableNotificationRow
+ */
+public class RowInflaterTask implements Abortable, AsyncLayoutInflater.OnInflateFinishedListener {
+    private RowInflationFinishedListener mListener;
+    private NotificationData.Entry mEntry;
+    private boolean mCancelled;
+
+    /**
+     * Inflates a new notificationView. This should not be called twice on this object
+     */
+    public void inflate(Context context, ViewGroup parent, NotificationData.Entry entry,
+            RowInflationFinishedListener listener) {
+        mListener = listener;
+        AsyncLayoutInflater inflater = new AsyncLayoutInflater(context);
+        mEntry = entry;
+        entry.setInflationTask(this);
+        inflater.inflate(R.layout.status_bar_notification_row, parent, this);
+    }
+
+    @Override
+    public void abort() {
+        mCancelled = true;
+    }
+
+    @Override
+    public void onInflateFinished(View view, int resid, ViewGroup parent) {
+        if (!mCancelled) {
+            mEntry.onInflationTaskFinished();
+            mListener.onInflationFinished((ExpandableNotificationRow) view);
+        }
+    }
+
+    public interface RowInflationFinishedListener {
+        void onInflationFinished(ExpandableNotificationRow row);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 1a9a40b..674a61c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -168,7 +168,8 @@
                         distance = mTranslationOnDown + distance;
                         distance = Math.max(0, distance);
                     }
-                    setTranslation(distance, false /* isReset */, false /* animateReset */);
+                    setTranslation(distance, false /* isReset */, false /* animateReset */,
+                            false /* force */);
                 }
                 break;
 
@@ -373,11 +374,12 @@
         targetView.finishAnimation(velocity, mAnimationEndRunnable);
     }
 
-    private void setTranslation(float translation, boolean isReset, boolean animateReset) {
+    private void setTranslation(float translation, boolean isReset, boolean animateReset,
+            boolean force) {
         translation = rightSwipePossible() ? translation : Math.max(0, translation);
         translation = leftSwipePossible() ? translation : Math.min(0, translation);
         float absTranslation = Math.abs(translation);
-        if (translation != mTranslation || isReset) {
+        if (translation != mTranslation || isReset || force) {
             KeyguardAffordanceView targetView = translation > 0 ? mLeftIcon : mRightIcon;
             KeyguardAffordanceView otherView = translation > 0 ? mRightIcon : mLeftIcon;
             float alpha = absTranslation / getMinTranslationAmount();
@@ -392,15 +394,15 @@
             boolean slowAnimation = isReset && isBelowFalsingThreshold();
             if (!isReset) {
                 updateIcon(targetView, radius, alpha + fadeOutAlpha * targetView.getRestingAlpha(),
-                        false, false, false, false);
+                        false, false, force, false);
             } else {
                 updateIcon(targetView, 0.0f, fadeOutAlpha * targetView.getRestingAlpha(),
-                        animateIcons, slowAnimation, false, forceNoCircleAnimation);
+                        animateIcons, slowAnimation, force, forceNoCircleAnimation);
             }
             updateIcon(otherView, 0.0f, fadeOutAlpha * otherView.getRestingAlpha(),
-                    animateIcons, slowAnimation, false, forceNoCircleAnimation);
+                    animateIcons, slowAnimation, force, forceNoCircleAnimation);
             updateIcon(mCenterIcon, 0.0f, fadeOutAlpha * mCenterIcon.getRestingAlpha(),
-                    animateIcons, slowAnimation, false, forceNoCircleAnimation);
+                    animateIcons, slowAnimation, force, forceNoCircleAnimation);
 
             mTranslation = translation;
         }
@@ -508,8 +510,12 @@
     }
 
     public void reset(boolean animate) {
+        reset(animate, false /* force */);
+    }
+
+    public void reset(boolean animate, boolean force) {
         cancelAnimation();
-        setTranslation(0.0f, true, animate);
+        setTranslation(0.0f, true, animate, force);
         mMotionCancelled = true;
         if (mSwipingInProgress) {
             mCallback.onSwipingAborted();
@@ -517,6 +523,10 @@
         }
     }
 
+    public void resetImmediately() {
+        reset(false /* animate */, true /* force */);
+    }
+
     public boolean isSwipingInProgress() {
         return mSwipingInProgress;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index f40de79..b191b91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -2477,6 +2477,14 @@
         }
     };
 
+    @Override
+    public void setTouchDisabled(boolean disabled) {
+        super.setTouchDisabled(disabled);
+        if (disabled && mAffordanceHelper.isSwipingInProgress() && !mIsLaunchTransitionRunning) {
+            mAffordanceHelper.resetImmediately();
+        }
+    }
+
     public void setDark(boolean dark) {
         mDark = dark;
         mKeyguardStatusView.setDark(dark);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index e86fd48..d342635 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -221,8 +221,11 @@
 
     public void setTouchDisabled(boolean disabled) {
         mTouchDisabled = disabled;
-        if (mTouchDisabled && mTracking) {
-            onTrackingStopped(true /* expanded */);
+        if (mTouchDisabled) {
+            cancelHeightAnimator();
+            if (mTracking) {
+                onTrackingStopped(true /* expanded */);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index 5690495..41fb5f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -579,6 +579,7 @@
                     .setComponent(aiaComponent)
                     .setAction(Intent.ACTION_VIEW)
                     .addCategory(Intent.CATEGORY_BROWSABLE)
+                    .addCategory("unique:" + System.currentTimeMillis())
                     .putExtra(Intent.EXTRA_PACKAGE_NAME, appInfo.packageName)
                     .putExtra(Intent.EXTRA_VERSION_CODE, appInfo.versionCode)
                     .putExtra(Intent.EXTRA_EPHEMERAL_FAILURE, pendingIntent);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 2be5b83..d29b356 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -277,8 +277,8 @@
                 mScrimInFront.setColors(mLockColors);
                 mScrimBehind.setColors(mLockColors);
             } else {
-                mScrimInFront.setColors(mSystemColors);
-                mScrimBehind.setColors(mSystemColors);
+                mScrimInFront.setColors(mSystemColors, true);
+                mScrimBehind.setColors(mSystemColors, true);
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 28895d5..38d514e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -207,6 +207,7 @@
 import com.android.systemui.statusbar.SignalClusterView;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.notification.InflationException;
+import com.android.systemui.statusbar.notification.RowInflaterTask;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.phone.StatusBarIconController.IconManager;
 import com.android.systemui.statusbar.phone.UnlockMethodCache.OnUnlockMethodChangedListener;
@@ -1598,12 +1599,12 @@
     private void abortExistingInflation(String key) {
         if (mPendingNotifications.containsKey(key)) {
             Entry entry = mPendingNotifications.get(key);
-            entry.abortInflation();
+            entry.abortTask();
             mPendingNotifications.remove(key);
         }
         Entry addedEntry = mNotificationData.get(key);
         if (addedEntry != null) {
-            addedEntry.abortInflation();
+            addedEntry.abortTask();
         }
     }
 
@@ -1620,7 +1621,7 @@
     }
 
     @Override
-    public void handleInflationException(StatusBarNotification notification, InflationException e) {
+    public void handleInflationException(StatusBarNotification notification, Exception e) {
         handleNotificationError(notification, e.getMessage());
     }
 
@@ -2501,29 +2502,28 @@
         }
 
         StringBuilder flagdbg = new StringBuilder();
-        flagdbg.append("disable: < ");
-        flagdbg.append(((state1 & StatusBarManager.DISABLE_EXPAND) != 0) ? "EXPAND" : "expand");
-        flagdbg.append(((diff1  & StatusBarManager.DISABLE_EXPAND) != 0) ? "* " : " ");
-        flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "ICONS" : "icons");
-        flagdbg.append(((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ICONS) != 0) ? "* " : " ");
-        flagdbg.append(((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "ALERTS" : "alerts");
-        flagdbg.append(((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS) != 0) ? "* " : " ");
-        flagdbg.append(((state1 & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "SYSTEM_INFO" : "system_info");
-        flagdbg.append(((diff1  & StatusBarManager.DISABLE_SYSTEM_INFO) != 0) ? "* " : " ");
-        flagdbg.append(((state1 & StatusBarManager.DISABLE_BACK) != 0) ? "BACK" : "back");
-        flagdbg.append(((diff1  & StatusBarManager.DISABLE_BACK) != 0) ? "* " : " ");
-        flagdbg.append(((state1 & StatusBarManager.DISABLE_HOME) != 0) ? "HOME" : "home");
-        flagdbg.append(((diff1  & StatusBarManager.DISABLE_HOME) != 0) ? "* " : " ");
-        flagdbg.append(((state1 & StatusBarManager.DISABLE_RECENT) != 0) ? "RECENT" : "recent");
-        flagdbg.append(((diff1  & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
-        flagdbg.append(((state1 & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
-        flagdbg.append(((diff1  & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
-        flagdbg.append(((state1 & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
-        flagdbg.append(((diff1  & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
-        flagdbg.append(((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "QUICK_SETTINGS"
-                : "quick_settings");
-        flagdbg.append(((diff2  & StatusBarManager.DISABLE2_QUICK_SETTINGS) != 0) ? "* " : " ");
-        flagdbg.append(">");
+        flagdbg.append("disable<");
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_EXPAND))                ? 'E' : 'e');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_EXPAND))                ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ICONS))    ? 'I' : 'i');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ICONS))    ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_NOTIFICATION_ALERTS))   ? 'A' : 'a');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_NOTIFICATION_ALERTS))   ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SYSTEM_INFO))           ? 'S' : 's');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_SYSTEM_INFO))           ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_BACK))                  ? 'B' : 'b');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_BACK))                  ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_HOME))                  ? 'H' : 'h');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_HOME))                  ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_RECENT))                ? 'R' : 'r');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_RECENT))                ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_CLOCK))                 ? 'C' : 'c');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_CLOCK))                 ? '!' : ' ');
+        flagdbg.append(0 != ((state1 & StatusBarManager.DISABLE_SEARCH))                ? 'S' : 's');
+        flagdbg.append(0 != ((diff1  & StatusBarManager.DISABLE_SEARCH))                ? '!' : ' ');
+        flagdbg.append(0 != ((state2 & StatusBarManager.DISABLE2_QUICK_SETTINGS))       ? 'Q' : 'q');
+        flagdbg.append(0 != ((diff2  & StatusBarManager.DISABLE2_QUICK_SETTINGS))       ? '!' : ' ');
+        flagdbg.append('>');
         Log.d(TAG, flagdbg.toString());
 
         if ((diff1 & StatusBarManager.DISABLE_EXPAND) != 0) {
@@ -4102,13 +4102,6 @@
             setBarState(StatusBarState.KEYGUARD);
         }
         updateKeyguardState(false /* goingToFullShade */, false /* fromShadeLocked */);
-        if (!mDeviceInteractive) {
-
-            // If the screen is off already, we need to disable touch events because these might
-            // collapse the panel after we expanded it, and thus we would end up with a blank
-            // Keyguard.
-            mNotificationPanel.setTouchDisabled(true);
-        }
         updatePanelExpansionForKeyguard();
         mLeaveOpenOnKeyguardHide = false;
         if (mDraggedDownRow != null) {
@@ -4915,6 +4908,12 @@
         mStackScroller.setAnimationsEnabled(false);
         mVisualStabilityManager.setScreenOn(false);
         updateVisibleToUser();
+
+        // We need to disable touch events because these might
+        // collapse the panel after we expanded it, and thus we would end up with a blank
+        // Keyguard.
+        mNotificationPanel.setTouchDisabled(true);
+        mStatusBarWindow.cancelCurrentTouch();
         if (mLaunchCameraOnFinishedGoingToSleep) {
             mLaunchCameraOnFinishedGoingToSleep = false;
 
@@ -6235,50 +6234,57 @@
                 entry.notification.getUser().getIdentifier());
 
         final StatusBarNotification sbn = entry.notification;
-        ExpandableNotificationRow row;
         if (entry.row != null) {
-            row = entry.row;
             entry.reset();
+            updateNotification(entry, pmUser, sbn, entry.row);
         } else {
-            // create the row view
-            LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
-                    Context.LAYOUT_INFLATER_SERVICE);
-            row = (ExpandableNotificationRow) inflater.inflate(R.layout.status_bar_notification_row,
-                    parent, false);
-            row.setExpansionLogger(this, entry.notification.getKey());
-            row.setGroupManager(mGroupManager);
-            row.setHeadsUpManager(mHeadsUpManager);
-            row.setRemoteInputController(mRemoteInputController);
-            row.setOnExpandClickListener(this);
-            row.setRemoteViewClickHandler(mOnClickHandler);
-            row.setInflationCallback(this);
-
-            // Get the app name.
-            // Note that Notification.Builder#bindHeaderAppName has similar logic
-            // but since this field is used in the guts, it must be accurate.
-            // Therefore we will only show the application label, or, failing that, the
-            // package name. No substitutions.
-            final String pkg = sbn.getPackageName();
-            String appname = pkg;
-            try {
-                final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
-                        PackageManager.MATCH_UNINSTALLED_PACKAGES
-                                | PackageManager.MATCH_DISABLED_COMPONENTS);
-                if (info != null) {
-                    appname = String.valueOf(pmUser.getApplicationLabel(info));
-                }
-            } catch (NameNotFoundException e) {
-                // Do nothing
-            }
-            row.setAppName(appname);
-            row.setOnDismissRunnable(() ->
-                    performRemoveNotification(row.getStatusBarNotification()));
-            row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
-            if (ENABLE_REMOTE_INPUT) {
-                row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
-            }
+            new RowInflaterTask().inflate(mContext, parent, entry,
+                    row -> {
+                        bindRow(entry, pmUser, sbn, row);
+                        updateNotification(entry, pmUser, sbn, row);
+                    });
         }
 
+    }
+
+    private void bindRow(Entry entry, PackageManager pmUser,
+            StatusBarNotification sbn, ExpandableNotificationRow row) {
+        row.setExpansionLogger(this, entry.notification.getKey());
+        row.setGroupManager(mGroupManager);
+        row.setHeadsUpManager(mHeadsUpManager);
+        row.setRemoteInputController(mRemoteInputController);
+        row.setOnExpandClickListener(this);
+        row.setRemoteViewClickHandler(mOnClickHandler);
+        row.setInflationCallback(this);
+
+        // Get the app name.
+        // Note that Notification.Builder#bindHeaderAppName has similar logic
+        // but since this field is used in the guts, it must be accurate.
+        // Therefore we will only show the application label, or, failing that, the
+        // package name. No substitutions.
+        final String pkg = sbn.getPackageName();
+        String appname = pkg;
+        try {
+            final ApplicationInfo info = pmUser.getApplicationInfo(pkg,
+                    PackageManager.MATCH_UNINSTALLED_PACKAGES
+                            | PackageManager.MATCH_DISABLED_COMPONENTS);
+            if (info != null) {
+                appname = String.valueOf(pmUser.getApplicationLabel(info));
+            }
+        } catch (NameNotFoundException e) {
+            // Do nothing
+        }
+        row.setAppName(appname);
+        row.setOnDismissRunnable(() ->
+                performRemoveNotification(row.getStatusBarNotification()));
+        row.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+        if (ENABLE_REMOTE_INPUT) {
+            row.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+        }
+    }
+
+    private void updateNotification(Entry entry, PackageManager pmUser,
+            StatusBarNotification sbn, ExpandableNotificationRow row) {
         row.setNeedsRedaction(needsRedaction(entry));
         boolean isLowPriority = mNotificationData.isAmbient(sbn.getKey());
         row.setIsLowPriority(isLowPriority);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 1a09d75..26e007c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -37,6 +37,7 @@
 import android.os.SystemClock;
 import android.util.AttributeSet;
 import android.view.ActionMode;
+import android.view.InputDevice;
 import android.view.InputQueue;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -84,6 +85,8 @@
     private ActionMode mFloatingActionMode;
     private FloatingToolbar mFloatingToolbar;
     private ViewTreeObserver.OnPreDrawListener mFloatingToolbarPreDrawListener;
+    private boolean mTouchCancelled;
+    private boolean mTouchActive;
 
     public StatusBarWindowView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -239,10 +242,20 @@
 
     @Override
     public boolean dispatchTouchEvent(MotionEvent ev) {
-        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN
-                && mNotificationPanel.isFullyCollapsed()) {
+        boolean isDown = ev.getActionMasked() == MotionEvent.ACTION_DOWN;
+        if (isDown && mNotificationPanel.isFullyCollapsed()) {
             mNotificationPanel.startExpandLatencyTracking();
         }
+        if (isDown) {
+            mTouchActive = true;
+            mTouchCancelled = false;
+        } else if (ev.getActionMasked() == MotionEvent.ACTION_UP
+                || ev.getActionMasked() == MotionEvent.ACTION_CANCEL) {
+            mTouchActive = false;
+        }
+        if (mTouchCancelled) {
+            return false;
+        }
         mFalsingManager.onTouchEvent(ev, getWidth(), getHeight());
         if (mBrightnessMirror != null && mBrightnessMirror.getVisibility() == VISIBLE) {
             // Disallow new pointers while the brightness mirror is visible. This is so that you
@@ -252,7 +265,7 @@
                 return false;
             }
         }
-        if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) {
+        if (isDown) {
             mStackScrollLayout.closeControlsIfOutsideTouch(ev);
         }
         if (mService.isDozing()) {
@@ -349,6 +362,18 @@
         }
     }
 
+    public void cancelCurrentTouch() {
+        if (mTouchActive) {
+            final long now = SystemClock.uptimeMillis();
+            MotionEvent event = MotionEvent.obtain(now, now,
+                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
+            event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
+            dispatchTouchEvent(event);
+            event.recycle();
+            mTouchCancelled = true;
+        }
+    }
+
     public class LayoutParams extends FrameLayout.LayoutParams {
 
         public boolean ignoreRightInset;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
index a2d1baf..c726189 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/EmergencyCryptkeeperText.java
@@ -47,6 +47,11 @@
         public void onPhoneStateChanged(int phoneState) {
             update();
         }
+
+        @Override
+        public void onRefreshCarrierInfo() {
+            update();
+        }
     };
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index fcb7289..efbf76b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -17,7 +17,10 @@
 
 import android.app.ActivityManager;
 import android.app.admin.DevicePolicyManager;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -28,16 +31,23 @@
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
+import android.os.AsyncTask;
+import android.os.Handler;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.security.KeyChain;
+import android.security.KeyChain.KeyChainConnection;
+import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.net.LegacyVpnInfo;
 import com.android.internal.net.VpnConfig;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.settings.CurrentUserTracker;
 
@@ -59,6 +69,8 @@
 
     private static final String VPN_BRANDED_META_DATA = "com.android.systemui.IS_BRANDED";
 
+    private static final int CA_CERT_LOADING_RETRY_TIME_IN_MS = 30_000;
+
     private final Context mContext;
     private final ConnectivityManager mConnectivityManager;
     private final IConnectivityManager mConnectivityManagerService;
@@ -73,6 +85,10 @@
     private int mCurrentUserId;
     private int mVpnUserId;
 
+    // Key: userId, Value: whether the user has CACerts installed
+    // Needs to be cached here since the query has to be asynchronous
+    private ArrayMap<Integer, Boolean> mHasCACerts = new ArrayMap<Integer, Boolean>();
+
     public SecurityControllerImpl(Context context) {
         super(context);
         mContext = context;
@@ -86,6 +102,11 @@
         mUserManager = (UserManager)
                 context.getSystemService(Context.USER_SERVICE);
 
+        IntentFilter filter = new IntentFilter();
+        filter.addAction(KeyChain.ACTION_TRUST_STORE_CHANGED);
+        context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null,
+                new Handler(Dependency.get(Dependency.BG_LOOPER)));
+
         // TODO: re-register network callback on user change.
         mConnectivityManager.registerNetworkCallback(REQUEST, mNetworkCallback);
         onUserSwitched(ActivityManager.getCurrentUser());
@@ -218,14 +239,16 @@
 
     @Override
     public boolean hasCACertInCurrentUser() {
-        //TODO: implement
-        return false;
+        Boolean hasCACerts = mHasCACerts.get(mCurrentUserId);
+        return hasCACerts != null && hasCACerts.booleanValue();
     }
 
     @Override
     public boolean hasCACertInWorkProfile() {
-        //TODO: implement
-        return false;
+        int userId = getWorkProfileUserId(mCurrentUserId);
+        if (userId == UserHandle.USER_NULL) return false;
+        Boolean hasCACerts = mHasCACerts.get(userId);
+        return hasCACerts != null && hasCACerts.booleanValue();
     }
 
     @Override
@@ -256,9 +279,16 @@
         } else {
             mVpnUserId = mCurrentUserId;
         }
+        refreshCACerts();
         fireCallbacks();
     }
 
+    private void refreshCACerts() {
+        new CACertLoader().execute(mCurrentUserId);
+        int workProfileId = getWorkProfileUserId(mCurrentUserId);
+        if (workProfileId != UserHandle.USER_NULL) new CACertLoader().execute(workProfileId);
+    }
+
     private String getNameForVpnConfig(VpnConfig cfg, UserHandle user) {
         if (cfg.legacy) {
             return mContext.getString(R.string.legacy_vpn_name);
@@ -348,4 +378,39 @@
             fireCallbacks();
         };
     };
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override public void onReceive(Context context, Intent intent) {
+            if (KeyChain.ACTION_TRUST_STORE_CHANGED.equals(intent.getAction())) {
+                refreshCACerts();
+            }
+        }
+    };
+
+    protected class CACertLoader extends AsyncTask<Integer, Void, Pair<Integer, Boolean> > {
+
+        @Override
+        protected Pair<Integer, Boolean> doInBackground(Integer... userId) {
+            try (KeyChainConnection conn = KeyChain.bindAsUser(mContext,
+                                                               UserHandle.of(userId[0]))) {
+                boolean hasCACerts = !(conn.getService().getUserCaAliases().getList().isEmpty());
+                return new Pair<Integer, Boolean>(userId[0], hasCACerts);
+            } catch (RemoteException | InterruptedException | AssertionError e) {
+                Log.i(TAG, e.getMessage());
+                new Handler(Dependency.get(Dependency.BG_LOOPER)).postDelayed(
+                        () -> new CACertLoader().execute(userId[0]),
+                        CA_CERT_LOADING_RETRY_TIME_IN_MS);
+                return new Pair<Integer, Boolean>(userId[0], null);
+            }
+        }
+
+        @Override
+        protected void onPostExecute(Pair<Integer, Boolean> result) {
+            if (DEBUG) Log.d(TAG, "onPostExecute " + result);
+            if (result.second != null) {
+                mHasCACerts.put(result.first, result.second);
+                fireCallbacks();
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
index cd85a76..ae8afe4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
+++ b/packages/SystemUI/src/com/android/systemui/util/NotificationChannels.java
@@ -30,6 +30,7 @@
     public static String SCREENSHOTS = "SCN";
     public static String GENERAL     = "GEN";
     public static String STORAGE     = "DSK";
+    public static String TVPIP       = "TPP";
 
     @VisibleForTesting
     static void createAll(Context context) {
@@ -55,6 +56,15 @@
                                 ? NotificationManager.IMPORTANCE_DEFAULT
                                 : NotificationManager.IMPORTANCE_LOW)
                 ));
+        if (isTv(context)) {
+            // TV specific notification channel for TV PIP controls.
+            // Importance should be {@link NotificationManager#IMPORTANCE_MAX} to have the highest
+            // priority, so it can be shown in all times.
+            nm.createNotificationChannel(new NotificationChannel(
+                    TVPIP,
+                    context.getString(R.string.notification_channel_tv_pip),
+                    NotificationManager.IMPORTANCE_MAX));
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index 8ac18e3..136aaad 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -38,6 +38,7 @@
 
 LOCAL_STATIC_ANDROID_LIBRARIES := \
     SystemUIPluginLib \
+    android-support-v4 \
     android-support-v7-recyclerview \
     android-support-v7-preference \
     android-support-v7-appcompat \
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index d57f813..8934460 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -28,17 +28,22 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import com.android.internal.hardware.AmbientDisplayConfiguration;
 import com.android.systemui.statusbar.phone.DozeParameters;
 import com.android.systemui.util.wakelock.WakeLock;
 import com.android.systemui.util.wakelock.WakeLockFake;
+import com.android.systemui.utils.hardware.FakeSensorManager;
 
 import org.junit.Before;
 import org.junit.BeforeClass;
-import org.junit.Ignore;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class DozeTriggersTest {
     private Context mContext;
     private DozeTriggers mTriggers;
@@ -46,7 +51,7 @@
     private DozeHostFake mHost;
     private AmbientDisplayConfiguration mConfig;
     private DozeParameters mParameters;
-    private SensorManagerFake mSensors;
+    private FakeSensorManager mSensors;
     private Handler mHandler;
     private WakeLock mWakeLock;
     private Instrumentation mInstrumentation;
@@ -65,7 +70,7 @@
         mHost = new DozeHostFake();
         mConfig = DozeConfigurationUtil.createMockConfig();
         mParameters = DozeConfigurationUtil.createMockParameters();
-        mSensors = new SensorManagerFake(mContext);
+        mSensors = new FakeSensorManager(mContext);
         mHandler = new Handler(Looper.getMainLooper());
         mWakeLock = new WakeLockFake();
 
@@ -76,29 +81,29 @@
     }
 
     @Test
-    @Ignore("setup crashes on virtual devices")
     public void testOnNotification_stillWorksAfterOneFailedProxCheck() throws Exception {
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
 
         mInstrumentation.runOnMainSync(()->{
             mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
-            mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.DOZE);
+            mTriggers.transitionTo(DozeMachine.State.INITIALIZED, DozeMachine.State.DOZE);
 
             mHost.callback.onNotificationHeadsUp();
         });
 
         mInstrumentation.runOnMainSync(() -> {
-            mSensors.PROXIMITY.sendProximityResult(false); /* Near */
+            mSensors.getMockProximitySensor().sendProximityResult(false); /* Near */
         });
 
         verify(mMachine, never()).requestState(any());
+        verify(mMachine, never()).requestPulse(anyInt());
 
         mInstrumentation.runOnMainSync(()->{
             mHost.callback.onNotificationHeadsUp();
         });
 
         mInstrumentation.runOnMainSync(() -> {
-            mSensors.PROXIMITY.sendProximityResult(true); /* Far */
+            mSensors.getMockProximitySensor().sendProximityResult(true); /* Far */
         });
 
         verify(mMachine).requestPulse(anyInt());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
index ddd6615..27d781d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTest.java
@@ -52,7 +52,6 @@
 
     @Before
     public void setUp() throws Exception {
-        TestableLooper.get(this).setAsMainLooper();
         mManagers = new ArrayList<>();
         QSTileHost host = new QSTileHost(mContext, null,
                 mock(StatusBarIconController.class));
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
index fbb25e5..15381b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationInflaterTest.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.service.notification.StatusBarNotification;
 import android.support.test.InstrumentationRegistry;
+import android.support.test.annotation.UiThreadTest;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 import android.widget.RemoteViews;
@@ -41,7 +42,6 @@
 import org.junit.runner.RunWith;
 
 import java.util.concurrent.CountDownLatch;
-import java.util.function.Function;
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -67,7 +67,7 @@
         mNotificationInflater.setInflationCallback(new NotificationInflater.InflationCallback() {
             @Override
             public void handleInflationException(StatusBarNotification notification,
-                    InflationException e) {
+                    Exception e) {
             }
 
             @Override
@@ -77,6 +77,7 @@
     }
 
     @Test
+    @UiThreadTest
     public void testIncreasedHeadsUpBeingUsed() {
         mNotificationInflater.setUsesIncreasedHeadsUpHeight(true);
         Notification.Builder builder = spy(mBuilder);
@@ -85,6 +86,7 @@
     }
 
     @Test
+    @UiThreadTest
     public void testIncreasedHeightBeingUsed() {
         mNotificationInflater.setUsesIncreasedHeight(true);
         Notification.Builder builder = spy(mBuilder);
@@ -124,10 +126,10 @@
 
     @Test
     public void testAsyncTaskRemoved() throws Exception {
-        mRow.getEntry().abortInflation();
+        mRow.getEntry().abortTask();
         runThenWaitForInflation(() -> mNotificationInflater.inflateNotificationViews(),
                 mNotificationInflater);
-        Assert.assertTrue(mRow.getEntry().getRunningTasks().size() == 0);
+        Assert.assertNull(mRow.getEntry().getRunningTask() );
     }
 
     public static void runThenWaitForInflation(Runnable block,
@@ -143,7 +145,7 @@
         inflater.setInflationCallback(new NotificationInflater.InflationCallback() {
             @Override
             public void handleInflationException(StatusBarNotification notification,
-                    InflationException e) {
+                    Exception e) {
                 if (!expectingException) {
                     exceptionHolder.setException(e);
                 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
index 87c4c66..f1a6653 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SecurityControllerTest.java
@@ -21,15 +21,29 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.doNothing;
 
 import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
+import android.content.pm.StringParceledListSlice;
 import android.net.ConnectivityManager;
+import android.security.IKeyChainService;
 import android.support.test.runner.AndroidJUnit4;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.systemui.statusbar.policy.SecurityController.SecurityControllerCallback;
 import com.android.systemui.SysuiTestCase;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.List;
+
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -37,15 +51,45 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class SecurityControllerTest extends SysuiTestCase {
+public class SecurityControllerTest extends SysuiTestCase implements SecurityControllerCallback {
     private final DevicePolicyManager mDevicePolicyManager = mock(DevicePolicyManager.class);
+    private final IKeyChainService.Stub mKeyChainService = mock(IKeyChainService.Stub.class);
     private SecurityControllerImpl mSecurityController;
+    private CountDownLatch mStateChangedLatch;
+
+    // implementing SecurityControllerCallback
+    @Override
+    public void onStateChanged() {
+        mStateChangedLatch.countDown();
+    }
 
     @Before
     public void setUp() throws Exception {
         mContext.addMockSystemService(Context.DEVICE_POLICY_SERVICE, mDevicePolicyManager);
         mContext.addMockSystemService(Context.CONNECTIVITY_SERVICE, mock(ConnectivityManager.class));
+
+        Intent intent = new Intent(IKeyChainService.class.getName());
+        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
+        mContext.addMockService(comp, mKeyChainService);
+
+        when(mKeyChainService.getUserCaAliases())
+                .thenReturn(new StringParceledListSlice(new ArrayList<String>()));
+        // Without this line, mKeyChainService gets wrapped in a proxy when Stub.asInterface() is
+        // used on it, and the mocking above does not work.
+        when(mKeyChainService.queryLocalInterface("android.security.IKeyChainService"))
+                .thenReturn(mKeyChainService);
+
         mSecurityController = new SecurityControllerImpl(mContext);
+
+        // Wait for one or two state changes from the CACertLoader(s) in the constructor of
+        // mSecurityController
+        mStateChangedLatch = new CountDownLatch(mSecurityController.hasWorkProfile() ? 2 : 1);
+        mSecurityController.addCallback(this);
+    }
+
+    @After
+    public void tearDown() {
+        mSecurityController.removeCallback(this);
     }
 
     @Test
@@ -62,4 +106,40 @@
         when(mDevicePolicyManager.getDeviceOwnerOrganizationName()).thenReturn("organization");
         assertEquals("organization", mSecurityController.getDeviceOwnerOrganizationName());
     }
+
+    @Test
+    public void testCaCertLoader() throws Exception {
+        assertTrue(mStateChangedLatch.await(3, TimeUnit.SECONDS));
+        assertFalse(mSecurityController.hasCACertInCurrentUser());
+
+        // With a CA cert
+
+        mStateChangedLatch = new CountDownLatch(1);
+
+        when(mKeyChainService.getUserCaAliases())
+                .thenReturn(new StringParceledListSlice(Arrays.asList("One CA Alias")));
+
+        mSecurityController.new CACertLoader()
+                           .execute(0);
+
+        assertTrue(mStateChangedLatch.await(3, TimeUnit.SECONDS));
+        assertTrue(mSecurityController.hasCACertInCurrentUser());
+
+        // Exception
+
+        mStateChangedLatch = new CountDownLatch(1);
+
+        when(mKeyChainService.getUserCaAliases())
+                .thenThrow(new AssertionError("Test AssertionError"))
+                .thenReturn(new StringParceledListSlice(new ArrayList<String>()));
+
+        mSecurityController.new CACertLoader()
+                           .execute(0);
+
+        assertFalse(mStateChangedLatch.await(3, TimeUnit.SECONDS));
+        assertTrue(mSecurityController.hasCACertInCurrentUser());
+        // The retry takes 30s
+        //assertTrue(mStateChangedLatch.await(31, TimeUnit.SECONDS));
+        //assertFalse(mSecurityController.hasCACertInCurrentUser());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/SensorManagerFake.java b/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
similarity index 60%
rename from packages/SystemUI/tests/src/com/android/systemui/doze/SensorManagerFake.java
rename to packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
index 5b4b891..30be665 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/SensorManagerFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/hardware/FakeSensorManager.java
@@ -11,10 +11,10 @@
  * 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.
+ * limitations under the License
  */
 
-package com.android.systemui.doze;
+package com.android.systemui.utils.hardware;
 
 import android.content.Context;
 import android.hardware.HardwareBuffer;
@@ -33,6 +33,8 @@
 import com.google.android.collect.Lists;
 
 import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -44,18 +46,38 @@
  * Note that this class ignores the "Handler" argument, so the test is responsible for calling the
  * listener on the right thread.
  */
-public class SensorManagerFake extends SensorManager {
+public class FakeSensorManager extends SensorManager {
 
-    public MockSensor PROXIMITY;
+    private final MockProximitySensor mMockProximitySensor;
 
-    public SensorManagerFake(Context context) {
-        PROXIMITY = new MockSensor(context.getSystemService(SensorManager.class)
-                .getDefaultSensor(Sensor.TYPE_PROXIMITY));
+    public FakeSensorManager(Context context) throws Exception {
+        Sensor proxSensor = context.getSystemService(SensorManager.class)
+                .getDefaultSensor(Sensor.TYPE_PROXIMITY);
+        if (proxSensor == null) {
+            // No prox? Let's create a fake one!
+            proxSensor = createSensor(Sensor.TYPE_PROXIMITY);
+        }
+        mMockProximitySensor = new MockProximitySensor(proxSensor);
+    }
+
+    public MockProximitySensor getMockProximitySensor() {
+        return mMockProximitySensor;
+    }
+
+    @Override
+    public Sensor getDefaultSensor(int type) {
+        Sensor s = super.getDefaultSensor(type);
+        if (s != null) {
+            return s;
+        }
+        // Our mock sensors aren't wakeup, and it's a pain to create them that way. Instead, just
+        // return non-wakeup sensors if we can't find a wakeup sensor.
+        return getDefaultSensor(type, false /* wakeup */);
     }
 
     @Override
     protected List<Sensor> getFullSensorList() {
-        return Lists.newArrayList(PROXIMITY.sensor);
+        return Lists.newArrayList(mMockProximitySensor.sensor);
     }
 
     @Override
@@ -65,8 +87,8 @@
 
     @Override
     protected void unregisterListenerImpl(SensorEventListener listener, Sensor sensor) {
-        if (sensor == PROXIMITY.sensor || sensor == null) {
-            PROXIMITY.listeners.remove(listener);
+        if (sensor == mMockProximitySensor.sensor || sensor == null) {
+            mMockProximitySensor.listeners.remove(listener);
         }
     }
 
@@ -74,8 +96,8 @@
     protected boolean registerListenerImpl(SensorEventListener listener, Sensor sensor,
             int delayUs,
             Handler handler, int maxReportLatencyUs, int reservedFlags) {
-        if (sensor == PROXIMITY.sensor) {
-            PROXIMITY.listeners.add(listener);
+        if (sensor == mMockProximitySensor.sensor) {
+            mMockProximitySensor.listeners.add(listener);
             return true;
         }
         return false;
@@ -141,11 +163,44 @@
         return false;
     }
 
-    public class MockSensor {
+    private Sensor createSensor(int type) throws Exception {
+        Constructor<Sensor> constr = Sensor.class.getDeclaredConstructor();
+        constr.setAccessible(true);
+        Sensor sensor = constr.newInstance();
+
+        setSensorType(sensor, type);
+        setSensorField(sensor, "mName", "Mock " + sensor.getStringType() + "/" + type);
+        setSensorField(sensor, "mVendor", "Mock Vendor");
+        setSensorField(sensor, "mVersion", 1);
+        setSensorField(sensor, "mHandle", -1);
+        setSensorField(sensor, "mMaxRange", 10);
+        setSensorField(sensor, "mResolution", 1);
+        setSensorField(sensor, "mPower", 1);
+        setSensorField(sensor, "mMinDelay", 1000);
+        setSensorField(sensor, "mMaxDelay", 1000000000);
+        setSensorField(sensor, "mFlags", 0);
+        setSensorField(sensor, "mId", -1);
+
+        return sensor;
+    }
+
+    private void setSensorField(Sensor sensor, String fieldName, Object value) throws Exception {
+        Field field = Sensor.class.getDeclaredField(fieldName);
+        field.setAccessible(true);
+        field.set(sensor, value);
+    }
+
+    private void setSensorType(Sensor sensor, int type) throws Exception {
+        Method setter = Sensor.class.getDeclaredMethod("setType", Integer.TYPE);
+        setter.setAccessible(true);
+        setter.invoke(sensor, type);
+    }
+
+    public class MockProximitySensor {
         final Sensor sensor;
         final ArraySet<SensorEventListener> listeners = new ArraySet<>();
 
-        private MockSensor(Sensor sensor) {
+        private MockProximitySensor(Sensor sensor) {
             this.sensor = sensor;
         }
 
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index f9b4372..b755dd6 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3957,11 +3957,23 @@
     // OS: O
     RUNNING_BACKGROUND_APPS_DIALOG = 944;
 
+    // FIELD - The delay from the start of the transition until we just call bindApplication on the
+    // client.
+    // OS: O
+    APP_TRANSITION_BIND_APPLICATION_DELAY_MS = 945;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // OPEN: Settings > System > Languages & input > Advanced > Lift to open camera
     SETTINGS_GESTURE_CAMERA_LIFT_TRIGGER = 986;
 
+    // OPEN: Settings > Battery > High Usage > Abnormal app page
+    // CATEGORY: SETTINGS
+    FUELGAUGE_ANOMALY_DETAIL = 987;
+
+    // OPEN: Settings > Battery > High Usage
+    DIALOG_HANDLE_ANOMALY = 988;
+
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
   }
diff --git a/proto/src/system_messages.proto b/proto/src/system_messages.proto
index ac544e8..8cecb4b 100644
--- a/proto/src/system_messages.proto
+++ b/proto/src/system_messages.proto
@@ -215,6 +215,10 @@
     // Package: com.android.systemui
     NOTE_LOGOUT_USER = 1011;
 
+    // Notify the user that a TV PIP is running.
+    // Package: com.android.systemui
+    NOTE_TV_PIP = 1100;
+
     // Communicate to the user about remote bugreports.
     // Package: android
     NOTE_REMOTE_BUGREPORT = 678432343;
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 05ad161..238bf0f 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -2895,6 +2895,7 @@
             mAllocationArray[0] = createTyped(rs, t, usage);
             if ((usage & USAGE_IO_INPUT) != 0) {
                 if (numAlloc > MAX_NUMBER_IO_INPUT_ALLOC) {
+                    mAllocationArray[0].destroy();
                     throw new RSIllegalArgumentException("Exceeds the max number of Allocations allowed: " +
                                                          MAX_NUMBER_IO_INPUT_ALLOC);
                 }
diff --git a/rs/java/android/renderscript/ScriptIntrinsicLUT.java b/rs/java/android/renderscript/ScriptIntrinsicLUT.java
index 69ff64a..e90462d 100644
--- a/rs/java/android/renderscript/ScriptIntrinsicLUT.java
+++ b/rs/java/android/renderscript/ScriptIntrinsicLUT.java
@@ -56,6 +56,10 @@
 
     }
 
+    public void destroy() {
+        mTables.destroy();
+        super.destroy();
+    }
 
     private void validate(int index, int value) {
         if (index < 0 || index > 255) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index ac81565..b2712ff 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -373,11 +373,6 @@
     }
 
     private void onPackageBroadcastReceived(Intent intent, int userId) {
-        if (!mUserManager.isUserUnlockingOrUnlocked(userId) ||
-                isProfileWithLockedParent(userId)) {
-            return;
-        }
-
         final String action = intent.getAction();
         boolean added = false;
         boolean changed = false;
@@ -408,7 +403,11 @@
         }
 
         synchronized (mLock) {
-            ensureGroupStateLoadedLocked(userId);
+            if (!mUserManager.isUserUnlockingOrUnlocked(userId) ||
+                    isProfileWithLockedParent(userId)) {
+                return;
+            }
+            ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ false);
 
             Bundle extras = intent.getExtras();
 
@@ -844,7 +843,7 @@
         mSecurityPolicy.enforceCallFromPackage(callingPackage);
 
         synchronized (mLock) {
-            ensureGroupStateLoadedLocked(userId);
+            ensureGroupStateLoadedLocked(userId, /* enforceUserUnlockingOrUnlocked */ false);
 
             // NOTE: The lookup is enforcing security across users by making
             // sure the caller can only access hosts it owns.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index b536ad9..e3398c9 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -118,7 +118,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
-                mUi.hideAll();
+                mUi.hideAll(null);
             }
         }
     };
@@ -213,7 +213,7 @@
                             if (!doit) {
                                 return true;
                             }
-                            handleActiveAutofillServiceRemoved(getChangingUserId());
+                            removeCachedServiceLocked(getChangingUserId());
                         }
                     }
                 }
@@ -470,9 +470,9 @@
         }
 
         @Override
-        public int startSession(IBinder activityToken, IBinder windowToken, IBinder appCallback,
-                AutofillId autofillId, Rect bounds, AutofillValue value, int userId,
-                boolean hasCallback, int flags, String packageName) {
+        public int startSession(IBinder activityToken, IBinder appCallback, AutofillId autofillId,
+                Rect bounds, AutofillValue value, int userId, boolean hasCallback, int flags,
+                String packageName) {
 
             activityToken = Preconditions.checkNotNull(activityToken, "activityToken");
             appCallback = Preconditions.checkNotNull(appCallback, "appCallback");
@@ -489,8 +489,8 @@
 
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = getServiceForUserLocked(userId);
-                return service.startSessionLocked(activityToken, getCallingUid(), windowToken,
-                        appCallback, autofillId, bounds, value, hasCallback, flags, packageName);
+                return service.startSessionLocked(activityToken, getCallingUid(), appCallback,
+                        autofillId, bounds, value, hasCallback, flags, packageName);
             }
         }
 
@@ -528,19 +528,6 @@
         }
 
         @Override
-        public void setWindow(int sessionId, IBinder windowToken) throws RemoteException {
-            windowToken = Preconditions.checkNotNull(windowToken, "windowToken");
-
-            synchronized (mLock) {
-                final AutofillManagerServiceImpl service = mServicesCache.get(
-                        UserHandle.getCallingUserId());
-                if (service != null) {
-                    service.setWindow(sessionId, getCallingUid(), windowToken);
-                }
-            }
-        }
-
-        @Override
         public void updateSession(int sessionId, AutofillId id, Rect bounds,
                 AutofillValue value, int action, int flags, int userId) {
             synchronized (mLock) {
@@ -602,6 +589,31 @@
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
 
+            boolean showHistory = true;
+            boolean uiOnly = false;
+            if (args != null) {
+                for (String arg : args) {
+                    switch(arg) {
+                        case "--no-history":
+                            showHistory = false;
+                            break;
+                        case "--ui-only":
+                            uiOnly = true;
+                            break;
+                        case "--help":
+                            pw.println("Usage: dumpsys autofill [--ui-only|--no-history]");
+                            return;
+                        default:
+                            throw new IllegalArgumentException("Invalid dump arg: " + arg);
+                    }
+                }
+            }
+
+            if (uiOnly) {
+                mUi.dump(pw);
+                return;
+            }
+
             boolean oldDebug = sDebug;
             try {
                 synchronized (mLock) {
@@ -624,8 +636,10 @@
                     }
                     mUi.dump(pw);
                 }
-                pw.println("Requests history:");
-                mRequestsHistory.reverseDump(fd, pw, args);
+                if (showHistory) {
+                    pw.println("Requests history:");
+                    mRequestsHistory.reverseDump(fd, pw, args);
+                }
             } finally {
                 setDebugLocked(oldDebug);
             }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4507eae..e315f9d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -19,17 +19,21 @@
 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
 import static android.view.autofill.AutofillManager.NO_SESSION;
 
+import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sVerbose;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager;
 import android.app.AppGlobals;
+import android.app.IActivityManager;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.graphics.Rect;
+import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -46,6 +50,7 @@
 import android.service.autofill.FillResponse;
 import android.service.autofill.IAutoFillService;
 import android.text.TextUtils;
+import android.util.ArrayMap;
 import android.util.LocalLog;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -72,6 +77,9 @@
     private static final String TAG = "AutofillManagerServiceImpl";
     private static final int MAX_SESSION_ID_CREATE_TRIES = 2048;
 
+    /** Minimum interval to prune abandoned sessions */
+    private static final int MAX_ABANDONED_SESSION_MILLIS = 30000;
+
     static final int MSG_SERVICE_SAVE = 1;
 
     private final int mUserId;
@@ -104,10 +112,10 @@
             mHandlerCallback, true);
 
     /**
-     * Cache of pending {@link Session}s, keyed by {@code activityToken}.
+     * Cache of pending {@link Session}s, keyed by sessionId.
      *
      * <p>They're kept until the {@link AutofillService} finished handling a request, an error
-     * occurs, or the session times out.
+     * occurs, or the session is abandoned.
      */
     @GuardedBy("mLock")
     private final SparseArray<Session> mSessions = new SparseArray<>();
@@ -116,6 +124,9 @@
     @GuardedBy("mLock")
     private FillEventHistory mEventHistory;
 
+    /** When was {@link PruneTask} last executed? */
+    private long mLastPrune = 0;
+
     AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
             int userId, AutoFillUI ui, boolean disabled) {
         mContext = context;
@@ -252,7 +263,7 @@
         }
     }
 
-    int startSessionLocked(@NonNull IBinder activityToken, int uid, @Nullable IBinder windowToken,
+    int startSessionLocked(@NonNull IBinder activityToken, int uid,
             @NonNull IBinder appCallbackToken, @NonNull AutofillId autofillId,
             @NonNull Rect virtualBounds, @Nullable AutofillValue value, boolean hasCallback,
             int flags, @NonNull String packageName) {
@@ -260,8 +271,11 @@
             return 0;
         }
 
-        final Session newSession = createSessionByTokenLocked(activityToken, uid, windowToken,
-                appCallbackToken, hasCallback, flags, packageName);
+        // Occasionally clean up abandoned sessions
+        pruneAbandonedSessionsLocked();
+
+        final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
+                hasCallback, flags, packageName);
         if (newSession == null) {
             return NO_SESSION;
         }
@@ -277,6 +291,20 @@
         return newSession.id;
     }
 
+    /**
+     * Remove abandoned sessions if needed.
+     */
+    private void pruneAbandonedSessionsLocked() {
+        long now = System.currentTimeMillis();
+        if (mLastPrune < now - MAX_ABANDONED_SESSION_MILLIS) {
+            mLastPrune = now;
+
+            if (mSessions.size() > 0) {
+                (new PruneTask()).execute();
+            }
+        }
+    }
+
     void finishSessionLocked(int sessionId, int uid) {
         if (!isEnabled()) {
             return;
@@ -331,8 +359,8 @@
     }
 
     private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
-            @Nullable IBinder windowToken, @NonNull IBinder appCallbackToken, boolean hasCallback,
-            int flags, @NonNull String packageName) {
+            @NonNull IBinder appCallbackToken, boolean hasCallback, int flags,
+            @NonNull String packageName) {
         // use random ids so that one app cannot know that another app creates sessions
         int sessionId;
         int tries = 0;
@@ -347,7 +375,7 @@
         } while (sessionId == NO_SESSION || mSessions.indexOfKey(sessionId) >= 0);
 
         final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
-                sessionId, uid, activityToken, windowToken, appCallbackToken, hasCallback,
+                sessionId, uid, activityToken, appCallbackToken, hasCallback,
                 mInfo.getServiceInfo().getComponentName(), packageName);
         mSessions.put(newSession.id, newSession);
 
@@ -374,24 +402,6 @@
         }
     }
 
-    /**
-     * Set the window the UI should get attached to
-     *
-     * @param sessionId The id of the session to restore
-     * @param uid UID of the process that tries to restore the session
-     * @param windowToken The window the activity is now in
-     */
-    boolean setWindow(int sessionId, int uid, @NonNull IBinder windowToken) {
-        final Session session = mSessions.get(sessionId);
-
-        if (session == null || uid != session.uid) {
-            return false;
-        } else {
-            session.switchWindow(windowToken);
-            return true;
-        }
-    }
-
     void updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
             AutofillValue value, int action, int flags) {
         final Session session = mSessions.get(sessionId);
@@ -513,6 +523,7 @@
         pw.print(prefix); pw.print("Default component: ");
             pw.println(mContext.getString(R.string.config_defaultAutofillService));
         pw.print(prefix); pw.print("Disabled: "); pw.println(mDisabled);
+        pw.print(prefix); pw.print("Last prune: "); pw.println(mLastPrune);
 
         final int size = mSessions.size();
         if (size == 0) {
@@ -604,4 +615,62 @@
                 + ", component=" + (mInfo != null
                 ? mInfo.getServiceInfo().getComponentName() : null) + "]";
     }
+
+    /** Task used to prune abandoned session */
+    private class PruneTask extends AsyncTask<Void, Void, Void> {
+        @Override
+        protected Void doInBackground(Void... ignored) {
+            int numSessionsToRemove;
+            ArrayMap<IBinder, Integer> sessionsToRemove;
+
+            synchronized (mLock) {
+                numSessionsToRemove = mSessions.size();
+                sessionsToRemove = new ArrayMap<>(numSessionsToRemove);
+
+                for (int i = 0; i < numSessionsToRemove; i++) {
+                    Session session = mSessions.valueAt(i);
+
+                    sessionsToRemove.put(session.getActivityTokenLocked(), session.id);
+                }
+            }
+
+            IActivityManager am = ActivityManager.getService();
+
+            // Only remove sessions which's activities are not known to the activity manager anymore
+            for (int i = 0; i < numSessionsToRemove; i++) {
+                try {
+                    // The activity manager cannot resolve activities that have been removed
+                    if (am.getActivityClassForToken(sessionsToRemove.keyAt(i)) != null) {
+                        sessionsToRemove.removeAt(i);
+                        i--;
+                        numSessionsToRemove--;
+                    }
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Cannot figure out if activity is finished", e);
+                }
+            }
+
+            synchronized (mLock) {
+                for (int i = 0; i < numSessionsToRemove; i++) {
+                    Session sessionToRemove = mSessions.get(sessionsToRemove.valueAt(i));
+
+                    if (sessionToRemove != null) {
+                        if (sessionToRemove.isSavingLocked()) {
+                            if (sVerbose) {
+                                Slog.v(TAG, "Session " + sessionToRemove.id + " is saving");
+                            }
+                        } else {
+                            if (sDebug) {
+                                Slog.i(TAG, "Prune session " + sessionToRemove.id + " ("
+                                    + sessionToRemove.getActivityTokenLocked() + ")");
+                            }
+                            sessionToRemove.removeSelfLocked();
+                        }
+                    }
+                }
+            }
+
+            return null;
+        }
+    }
 }
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index 68ade63..8d947b9 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -40,6 +40,10 @@
      */
     public static boolean sVerbose = false;
 
+    private Helper() {
+        throw new UnsupportedOperationException("contains static members only");
+    }
+
     static void append(StringBuilder builder, Bundle bundle) {
         if (bundle == null || !sVerbose) {
             builder.append("null");
@@ -62,10 +66,6 @@
         return builder.toString();
     }
 
-    private Helper() {
-        throw new UnsupportedOperationException("contains static members only");
-    }
-
     static ViewNode findViewNodeById(@NonNull AssistStructure structure, @NonNull AutofillId id) {
         final int size = structure.getWindowNodeCount();
         for (int i = 0; i < size; i++) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 9d03fde..3f78fb8 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -25,9 +25,12 @@
 import static android.view.autofill.AutofillManager.ACTION_VIEW_ENTERED;
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
 
+import static com.android.server.autofill.Helper.findViewNodeById;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sVerbose;
-import static com.android.server.autofill.Helper.findViewNodeById;
+import static com.android.server.autofill.ViewState.STATE_AUTOFILLED;
+import static com.android.server.autofill.ViewState.STATE_FILLABLE;
+import static com.android.server.autofill.ViewState.STATE_RESTARTED_SESSION;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -116,9 +119,6 @@
     @GuardedBy("mLock")
     @NonNull private IBinder mActivityToken;
 
-    @GuardedBy("mLock")
-    @NonNull private IBinder mWindowToken;
-
     /** Package name of the app that is auto-filled */
     @NonNull private final String mPackageName;
 
@@ -173,6 +173,10 @@
     @GuardedBy("mLock")
     private boolean mDestroyed;
 
+    /** Whether the session is currently saving */
+    @GuardedBy("mLock")
+    private boolean mIsSaving;
+
     /**
      * Receiver of assist data from the app's {@link Activity}.
      */
@@ -251,16 +255,21 @@
                 continue;
             }
 
-            final AutofillValue initialValue = viewState.getInitialValue();
+            final AutofillValue currentValue = viewState.getCurrentValue();
             final AutofillValue filledValue = viewState.getAutofilledValue();
             final AutofillOverlay overlay = new AutofillOverlay();
-            if (filledValue != null && !filledValue.equals(initialValue)) {
-                overlay.value = filledValue;
+
+            // Sanitizes the value if the current value matches what the service sent.
+            if (filledValue != null && filledValue.equals(currentValue)) {
+                overlay.value = currentValue;
             }
+
             if (mCurrentViewId != null) {
+                // Updates the focus value.
                 overlay.focused = mCurrentViewId.equals(viewState.id);
+                // Sanitizes the value of the focused field in a manual request.
                 if (overlay.focused && (flags & FLAG_MANUAL_REQUEST) != 0) {
-                    overlay.value = node.getAutofillValue();
+                    overlay.value = currentValue;
                 }
             }
             node.setAutofillOverlay(overlay);
@@ -329,7 +338,7 @@
     Session(@NonNull AutofillManagerServiceImpl service, @NonNull AutoFillUI ui,
             @NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
             @NonNull Object lock, int sessionId, int uid, @NonNull IBinder activityToken,
-            @Nullable IBinder windowToken, @NonNull IBinder client, boolean hasCallback,
+            @NonNull IBinder client, boolean hasCallback,
             @NonNull ComponentName componentName, @NonNull String packageName) {
         id = sessionId;
         this.uid = uid;
@@ -339,7 +348,6 @@
         mHandlerCaller = handlerCaller;
         mRemoteFillService = new RemoteFillService(context, componentName, userId, this);
         mActivityToken = activityToken;
-        mWindowToken = windowToken;
         mHasCallback = hasCallback;
         mPackageName = packageName;
         mClient = IAutoFillManagerClient.Stub.asInterface(client);
@@ -352,28 +360,11 @@
      *
      * @return The activity token
      */
-    IBinder getActivityTokenLocked() {
+    @NonNull IBinder getActivityTokenLocked() {
         return mActivityToken;
     }
 
     /**
-     * Sets new window  for this session.
-     *
-     * @param newWindow The window the Ui should be attached to. Can be {@code null} if no
-     *                  further UI is needed.
-     */
-    void switchWindow(@NonNull IBinder newWindow) {
-        synchronized (mLock) {
-            if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#switchWindow() rejected - session: "
-                        + id + " destroyed");
-                return;
-            }
-            mWindowToken = newWindow;
-        }
-    }
-
-    /**
      * Sets new activity and client for this session.
      *
      * @param newActivity The token of the new activity
@@ -407,7 +398,7 @@
         }
         if (response == null) {
             if ((requestFlags & FLAG_MANUAL_REQUEST) != 0) {
-                getUiForShowing().showError(R.string.autofill_error_cannot_autofill);
+                getUiForShowing().showError(R.string.autofill_error_cannot_autofill, this);
             }
             // Nothing to be done, but need to notify client.
             notifyUnavailableToClient();
@@ -457,7 +448,7 @@
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName);
         mMetricsLogger.write(log);
 
-        getUiForShowing().showError(message);
+        getUiForShowing().showError(message, this);
         removeSelf();
     }
 
@@ -465,6 +456,8 @@
     @Override
     public void onSaveRequestSuccess(@NonNull String servicePackageName) {
         synchronized (mLock) {
+            mIsSaving = false;
+
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onSaveRequestSuccess() rejected - session: "
                         + id + " destroyed");
@@ -487,6 +480,8 @@
     public void onSaveRequestFailure(@Nullable CharSequence message,
             @NonNull String servicePackageName) {
         synchronized (mLock) {
+            mIsSaving = false;
+
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onSaveRequestFailure() rejected - session: "
                         + id + " destroyed");
@@ -500,7 +495,7 @@
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName);
         mMetricsLogger.write(log);
 
-        getUiForShowing().showError(message);
+        getUiForShowing().showError(message, this);
         removeSelf();
     }
 
@@ -587,6 +582,8 @@
     @Override
     public void cancelSave() {
         synchronized (mLock) {
+            mIsSaving = false;
+
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#cancelSave() rejected - session: "
                         + id + " destroyed");
@@ -609,8 +606,8 @@
             if (id.equals(mCurrentViewId)) {
                 try {
                     final ViewState view = mViewStates.get(id);
-                    mClient.requestShowFillUi(this.id, mWindowToken, id, width, height,
-                            view.getVirtualBounds(), presenter);
+                    mClient.requestShowFillUi(this.id, id, width, height, view.getVirtualBounds(),
+                            presenter);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "Error requesting to show fill UI", e);
                 }
@@ -630,7 +627,7 @@
             // NOTE: We allow this call in a destroyed state as the UI is
             // asked to go away after we get destroyed, so let it do that.
             try {
-                mClient.requestHideFillUi(this.id, mWindowToken, id);
+                mClient.requestHideFillUi(this.id, id);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error requesting to hide fill UI", e);
             }
@@ -670,6 +667,8 @@
         } else {
             final Parcelable result = data.getParcelable(
                     AutofillManager.EXTRA_AUTHENTICATION_RESULT);
+            if (sVerbose) Slog.d(TAG, "setAuthenticationResultLocked() for " + result);
+
             if (result instanceof FillResponse) {
                 FillResponse response = (FillResponse) result;
 
@@ -678,6 +677,16 @@
                 mResponseWaitingAuth = null;
                 if (requestIndex >= 0) {
                     response.setRequestId(mResponses.keyAt(requestIndex));
+                    if (response.getDatasets() == null || response.getDatasets().isEmpty()) {
+                        // TODO(b/37424539): there is a race condition that causes the authentication
+                        // dialog to be shown again after the service authreplied with a no-datasets
+                        // response. We're fixing it by hiding the UI when that happens, but that
+                        // sounds like a hack - hopefully the real problem will go away when we
+                        // refactor auth to support partitions; if it doesn't, we need to
+                        // investigate it further (it can be reproduced by running
+                        // LoginActivityTest.testFillResponseAuthServiceHasNoData())
+                        mUi.hideAll(this);
+                    }
                     processResponseLocked(response);
                 } else {
                     Slog.e(TAG, "Error cannot find id for auth response");
@@ -821,7 +830,10 @@
             }
             if (atLeastOneChanged) {
                 mService.setSaveShown();
-                getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName);
+                getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName,
+                        this);
+
+                mIsSaving = true;
                 return false;
             }
         }
@@ -835,6 +847,13 @@
     }
 
     /**
+     * Returns whether the session is currently showing the save UI
+     */
+    boolean isSavingLocked() {
+        return mIsSaving;
+    }
+
+    /**
      * Calls service when user requested save.
      */
     void callSaveLocked() {
@@ -887,6 +906,40 @@
     }
 
     /**
+     * Starts (if necessary) a new fill request upon entering a view.
+     *
+     * <p>A new request will be started in 2 scenarios:
+     * <ol>
+     *   <li>If the user manually requested autofill after the view was already filled.
+     *   <li>If the view is part of a new partition.
+     * </ol>
+     *
+     * @param id The id of the view that is entered.
+     * @param viewState The view that is entered.
+     * @param flags The flag that was passed by the AutofillManager.
+     */
+    private void requestNewFillResponseIfNecessaryLocked(@NonNull AutofillId id,
+            @NonNull ViewState viewState, int flags) {
+        // First check if this is a manual request after view was autofilled.
+        final int state = viewState.getState();
+        final boolean restart = (state & STATE_AUTOFILLED) != 0
+                && (flags & FLAG_MANUAL_REQUEST) != 0;
+        if (restart) {
+            if (sDebug) Slog.d(TAG, "Re-starting session on view  " + id);
+            viewState.setState(STATE_RESTARTED_SESSION);
+            requestNewFillResponseLocked(flags);
+            return;
+        }
+
+        // If it's not, then check if it it should start a partition.
+        if (shouldStartNewPartitionLocked(id)) {
+            if (sDebug) Slog.d(TAG, "Starting partition for view id " + id);
+            viewState.setState(ViewState.STATE_STARTED_PARTITION);
+            requestNewFillResponseLocked(flags);
+        }
+    }
+
+    /**
      * Determines if a new partition should be started for an id.
      *
      * @param id The id of the view that is entered
@@ -942,15 +995,15 @@
                     + id + " destroyed");
             return;
         }
+        if (sVerbose) {
+            Slog.v(TAG, "updateLocked(): id=" + id + ", action=" + action + ", flags=" + flags);
+        }
         ViewState viewState = mViewStates.get(id);
 
         if (viewState == null) {
             if (action == ACTION_START_SESSION || action == ACTION_VALUE_CHANGED
                     || action == ACTION_VIEW_ENTERED) {
-                if (sVerbose) {
-                    Slog.v(TAG,
-                            "Creating viewState for " + id + " on " + getActionAsString(action));
-                }
+                if (sVerbose) Slog.v(TAG, "Creating viewState for " + id + " on " + action);
                 boolean isIgnored = isIgnoredLocked(id);
                 viewState = new ViewState(this, id, value, this,
                         isIgnored ? ViewState.STATE_IGNORED : ViewState.STATE_INITIAL);
@@ -960,7 +1013,7 @@
                     return;
                 }
             } else {
-                if (sVerbose) Slog.v(TAG, "Ignored " + getActionAsString(action) + " for " + id);
+                if (sVerbose) Slog.v(TAG, "Ignored action " + action + " for " + id);
                 return;
             }
         }
@@ -989,24 +1042,21 @@
 
                     //..and the UI
                     if (value.isText()) {
-                        getUiForShowing().filterFillUi(value.getTextValue().toString());
+                        getUiForShowing().filterFillUi(value.getTextValue().toString(), this);
                     } else {
-                        getUiForShowing().filterFillUi(null);
+                        getUiForShowing().filterFillUi(null, this);
                     }
                 }
                 break;
             case ACTION_VIEW_ENTERED:
-                if (shouldStartNewPartitionLocked(id)) {
-                    if (sDebug) {
-                        Slog.d(TAG, "Starting partition for view id " + viewState.id);
-                    }
-                    viewState.setState(ViewState.STATE_STARTED_PARTITION);
-                    requestNewFillResponseLocked(flags);
+                if (sVerbose && virtualBounds != null) {
+                    Slog.w(TAG, "entered on virtual child " + id + ": " + virtualBounds);
                 }
+                requestNewFillResponseIfNecessaryLocked(id, viewState, flags);
 
                 // Remove the UI if the ViewState has changed.
                 if (mCurrentViewId != viewState.id) {
-                    mUi.hideFillUi(mCurrentViewId != null ? mCurrentViewId : null);
+                    mUi.hideFillUi(this);
                     mCurrentViewId = viewState.id;
                 }
 
@@ -1015,7 +1065,8 @@
                 break;
             case ACTION_VIEW_EXITED:
                 if (mCurrentViewId == viewState.id) {
-                    mUi.hideFillUi(viewState.id);
+                    if (sVerbose) Slog.d(TAG, "Exiting view " + id);
+                    mUi.hideFillUi(this);
                     mCurrentViewId = null;
                 }
                 break;
@@ -1052,11 +1103,7 @@
             filterText = value.getTextValue().toString();
         }
 
-        getUiForShowing().showFillUi(filledId, response, filterText, mPackageName);
-    }
-
-    String getActionAsString(int flag) {
-        return DebugUtils.flagsToString(AutofillManager.class, "ACTION_", flag);
+        getUiForShowing().showFillUi(filledId, response, filterText, mPackageName, this);
     }
 
     boolean isDestroyed() {
@@ -1075,10 +1122,9 @@
         synchronized (mLock) {
             if (!mHasCallback) return;
             try {
-                mClient.notifyNoFillUi(id, mWindowToken, mCurrentViewId);
+                mClient.notifyNoFillUi(id, mCurrentViewId);
             } catch (RemoteException e) {
-                Slog.e(TAG, "Error notifying client no fill UI: windowToken=" + mWindowToken
-                        + " id=" + mCurrentViewId, e);
+                Slog.e(TAG, "Error notifying client no fill UI: id=" + mCurrentViewId, e);
             }
         }
     }
@@ -1117,14 +1163,15 @@
     }
 
     private void processResponseLocked(@NonNull FillResponse response) {
+        final int requestId = response.getRequestId();
         if (sVerbose) {
-            Slog.v(TAG, "processResponseLocked(mCurrentViewId=" + mCurrentViewId + "):" + response);
+            Slog.v(TAG, "processResponseLocked(): mCurrentViewId=" + mCurrentViewId
+                    + ", reqId=" + requestId + ", resp=" + response);
         }
 
         if (mResponses == null) {
             mResponses = new SparseArray<>(4);
         }
-        final int requestId = response.getRequestId();
         mResponses.put(requestId, response);
         mClientState = response.getClientState();
 
@@ -1305,6 +1352,7 @@
         pw.print(prefix); pw.print("mCurrentViewId: "); pw.println(mCurrentViewId);
         pw.print(prefix); pw.print("mViewStates size: "); pw.println(mViewStates.size());
         pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
+        pw.print(prefix); pw.print("mIsSaving: "); pw.println(mIsSaving);
         final String prefix2 = prefix + "  ";
         for (Map.Entry<AutofillId, ViewState> entry : mViewStates.entrySet()) {
             pw.print(prefix); pw.print("State for id "); pw.println(entry.getKey());
@@ -1344,8 +1392,7 @@
             }
             try {
                 if (sDebug) Slog.d(TAG, "autoFillApp(): the buck is on the app: " + dataset);
-                mClient.autofill(id, mWindowToken, dataset.getFieldIds(),
-                        dataset.getFieldValues());
+                mClient.autofill(id, dataset.getFieldIds(), dataset.getFieldValues());
                 setViewStatesLocked(null, dataset, ViewState.STATE_AUTOFILLED);
             } catch (RemoteException e) {
                 Slog.w(TAG, "Error autofilling activity: " + e);
@@ -1365,8 +1412,8 @@
             return;
         }
         mRemoteFillService.destroy();
-        mUi.hideAll();
-        mUi.setCallback(null);
+        mUi.hideAll(this);
+        mUi.clearCallback(this);
         mDestroyed = true;
         mMetricsLogger.action(MetricsEvent.AUTOFILL_SESSION_FINISHED, mPackageName);
     }
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index d114e14..561c603 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -47,23 +47,25 @@
     private static final String TAG = "ViewState";
 
     // NOTE: state constants must be public because of flagstoString().
-    public static final int STATE_UNKNOWN = 0x00;
+    public static final int STATE_UNKNOWN = 0x000;
     /** Initial state. */
-    public static final int STATE_INITIAL = 0x01;
+    public static final int STATE_INITIAL = 0x001;
     /** View id is present in a dataset returned by the service. */
-    public static final int STATE_FILLABLE = 0x02;
+    public static final int STATE_FILLABLE = 0x002;
     /** View was autofilled after user selected a dataset. */
-    public static final int STATE_AUTOFILLED = 0x04;
+    public static final int STATE_AUTOFILLED = 0x004;
     /** View value was changed, but not by the service. */
-    public static final int STATE_CHANGED = 0x08;
+    public static final int STATE_CHANGED = 0x008;
     /** Set only in the View that started a session. */
-    public static final int STATE_STARTED_SESSION = 0x10;
+    public static final int STATE_STARTED_SESSION = 0x010;
     /** View that started a new partition when focused on. */
-    public static final int STATE_STARTED_PARTITION = 0x20;
+    public static final int STATE_STARTED_PARTITION = 0x020;
     /** User select a dataset in this view, but service must authenticate first. */
-    public static final int STATE_WAITING_DATASET_AUTH = 0x40;
+    public static final int STATE_WAITING_DATASET_AUTH = 0x040;
     /** Service does not care about this view. */
-    public static final int STATE_IGNORED = 0x80;
+    public static final int STATE_IGNORED = 0x080;
+    /** User manually request autofill in this view, after it was already autofilled. */
+    public static final int STATE_RESTARTED_SESSION = 0x100;
 
     public final AutofillId id;
 
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 086742e..9eaabfe2 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -74,31 +74,43 @@
         mContext = context;
     }
 
-    public void setCallback(@Nullable AutoFillUiCallback callback) {
+    public void setCallback(@NonNull AutoFillUiCallback callback) {
         mHandler.post(() -> {
             if (mCallback != callback) {
-                hideAllUiThread();
+                if (mCallback != null) {
+                    hideAllUiThread(mCallback);
+                }
+
                 mCallback = callback;
             }
         });
     }
 
+    public void clearCallback(@NonNull AutoFillUiCallback callback) {
+        mHandler.post(() -> {
+            if (mCallback == callback) {
+                hideAllUiThread(callback);
+                mCallback = null;
+            }
+        });
+    }
+
     /**
      * Displays an error message to the user.
      */
-    public void showError(int resId) {
-        showError(mContext.getString(resId));
+    public void showError(int resId, @NonNull AutoFillUiCallback callback) {
+        showError(mContext.getString(resId), callback);
     }
 
     /**
      * Displays an error message to the user.
      */
-    public void showError(@Nullable CharSequence message) {
+    public void showError(@Nullable CharSequence message, @NonNull AutoFillUiCallback callback) {
         mHandler.post(() -> {
-            if (!hasCallback()) {
+            if (mCallback != callback) {
                 return;
             }
-            hideAllUiThread();
+            hideAllUiThread(callback);
             if (!TextUtils.isEmpty(message)) {
                 Toast.makeText(mContext, message, Toast.LENGTH_LONG).show();
             }
@@ -108,8 +120,8 @@
     /**
      * Hides the fill UI.
      */
-    public void hideFillUi(AutofillId id) {
-        mHandler.post(this::hideFillUiUiThread);
+    public void hideFillUi(@NonNull AutoFillUiCallback callback) {
+        mHandler.post(() -> hideFillUiUiThread(callback));
     }
 
     /**
@@ -117,12 +129,12 @@
      *
      * @param filterText The filter prefix.
      */
-    public void filterFillUi(@Nullable String filterText) {
+    public void filterFillUi(@Nullable String filterText, @NonNull AutoFillUiCallback callback) {
         mHandler.post(() -> {
-            if (!hasCallback()) {
+            if (callback != mCallback) {
                 return;
             }
-            hideSaveUiUiThread();
+            hideSaveUiUiThread(callback);
             if (mFillUi != null) {
                 mFillUi.setFilterText(filterText);
             }
@@ -136,9 +148,11 @@
      * @param response the current fill response
      * @param filterText text of the view to be filled
      * @param packageName package name of the activity that is filled
+     * @param callback Identifier for the caller
      */
     public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
-            @Nullable String filterText, @NonNull String packageName) {
+            @Nullable String filterText, @NonNull String packageName,
+            @NonNull AutoFillUiCallback callback) {
         if (sDebug) {
             Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + filterText);
         }
@@ -150,16 +164,16 @@
                         response.getDatasets() == null ? 0 : response.getDatasets().size());
 
         mHandler.post(() -> {
-            if (!hasCallback()) {
+            if (callback != mCallback) {
                 return;
             }
-            hideAllUiThread();
+            hideAllUiThread(callback);
             mFillUi = new FillUi(mContext, response, focusedId,
                     filterText, new FillUi.Callback() {
                 @Override
                 public void onResponsePicked(FillResponse response) {
                     log.setType(MetricsProto.MetricsEvent.TYPE_DETAIL);
-                    hideFillUiUiThread();
+                    hideFillUiUiThread(callback);
                     if (mCallback != null) {
                         mCallback.authenticate(response.getRequestId(),
                                 response.getAuthentication(), response.getClientState());
@@ -169,7 +183,7 @@
                 @Override
                 public void onDatasetPicked(Dataset dataset) {
                     log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
-                    hideFillUiUiThread();
+                    hideFillUiUiThread(callback);
                     if (mCallback != null) {
                         mCallback.fill(response.getRequestId(), dataset);
                     }
@@ -178,7 +192,7 @@
                 @Override
                 public void onCanceled() {
                     log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
-                    hideFillUiUiThread();
+                    hideFillUiUiThread(callback);
                 }
 
                 @Override
@@ -218,7 +232,7 @@
      * Shows the UI asking the user to save for autofill.
      */
     public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info,
-            @NonNull String packageName) {
+            @NonNull String packageName, @NonNull AutoFillUiCallback callback) {
         int numIds = 0;
         numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
         numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
@@ -228,16 +242,16 @@
                         MetricsProto.MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds);
 
         mHandler.post(() -> {
-            if (!hasCallback()) {
+            if (callback != mCallback) {
                 return;
             }
-            hideAllUiThread();
+            hideAllUiThread(callback);
             mSaveUi = new SaveUi(mContext, providerLabel, info,
                     new SaveUi.OnSaveListener() {
                 @Override
                 public void onSave() {
                     log.setType(MetricsProto.MetricsEvent.TYPE_ACTION);
-                    hideSaveUiUiThread();
+                    hideSaveUiUiThread(callback);
                     if (mCallback != null) {
                         mCallback.save();
                     }
@@ -246,7 +260,7 @@
                 @Override
                 public void onCancel(IntentSender listener) {
                     log.setType(MetricsProto.MetricsEvent.TYPE_DISMISS);
-                    hideSaveUiUiThread();
+                    hideSaveUiUiThread(callback);
                     if (listener != null) {
                         try {
                             listener.sendIntent(mContext, 0, null, null, null);
@@ -264,6 +278,10 @@
                 public void onDestroy() {
                     if (log.getType() == MetricsProto.MetricsEvent.TYPE_UNKNOWN) {
                         log.setType(MetricsProto.MetricsEvent.TYPE_CLOSE);
+
+                        if (mCallback != null) {
+                            mCallback.cancelSave();
+                        }
                     }
                     mMetricsLogger.write(log);
                 }
@@ -274,46 +292,47 @@
     /**
      * Hides all UI affordances.
      */
-    public void hideAll() {
-        mHandler.post(this::hideAllUiThread);
+    public void hideAll(@Nullable AutoFillUiCallback callback) {
+        mHandler.post(() -> hideAllUiThread(callback));
     }
 
     public void dump(PrintWriter pw) {
         pw.println("Autofill UI");
         final String prefix = "  ";
         final String prefix2 = "    ";
-        pw.print(prefix); pw.print("showsSaveUi: "); pw.println(mSaveUi != null);
         if (mFillUi != null) {
             pw.print(prefix); pw.println("showsFillUi: true");
             mFillUi.dump(pw, prefix2);
         } else {
             pw.print(prefix); pw.println("showsFillUi: false");
         }
+        if (mSaveUi != null) {
+            pw.print(prefix); pw.println("showsSaveUi: true");
+            mSaveUi.dump(pw, prefix2);
+        } else {
+            pw.print(prefix); pw.println("showsSaveUi: false");
+        }
     }
 
     @android.annotation.UiThread
-    private void hideFillUiUiThread() {
-        if (mFillUi != null) {
+    private void hideFillUiUiThread(@Nullable AutoFillUiCallback callback) {
+        if (mFillUi != null && (callback == null || callback == mCallback)) {
             mFillUi.destroy();
             mFillUi = null;
         }
     }
 
     @android.annotation.UiThread
-    private void hideSaveUiUiThread() {
-        if (mSaveUi != null) {
+    private void hideSaveUiUiThread(@Nullable AutoFillUiCallback callback) {
+        if (mSaveUi != null && (callback == null || callback == mCallback)) {
             mSaveUi.destroy();
             mSaveUi = null;
         }
     }
 
     @android.annotation.UiThread
-    private void hideAllUiThread() {
-        hideFillUiUiThread();
-        hideSaveUiUiThread();
-    }
-
-    private boolean hasCallback() {
-        return mCallback != null;
+    private void hideAllUiThread(@Nullable AutoFillUiCallback callback) {
+        hideFillUiUiThread(callback);
+        hideSaveUiUiThread(callback);
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/ui/FillUi.java b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
index dd297a6..31b4b55 100644
--- a/services/autofill/java/com/android/server/autofill/ui/FillUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/FillUi.java
@@ -16,6 +16,7 @@
 package com.android.server.autofill.ui;
 
 import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -265,8 +266,11 @@
         mContentWidth = 0;
         mContentHeight = 0;
 
-        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
-        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.UNSPECIFIED, 0);
+        final int widthMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.x,
+                MeasureSpec.AT_MOST);
+        final int heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxSize.y,
+                MeasureSpec.AT_MOST);
+
         final int itemCount = Math.min(mAdapter.getCount(), VISIBLE_OPTIONS_MAX_COUNT);
         for (int i = 0; i < itemCount; i++) {
             View view = mAdapter.getItem(i).getView();
@@ -334,6 +338,11 @@
         @Override
         public void show(WindowManager.LayoutParams p, Rect transitionEpicenter,
                 boolean fitsSystemWindows, int layoutDirection) {
+            if (sVerbose) {
+                Slog.v(TAG, "AutofillWindowPresenter.show(): fit=" + fitsSystemWindows
+                        + ", epicenter="+ transitionEpicenter + ", dir=" + layoutDirection
+                        + ", params=" + p);
+            }
             UiThread.getHandler().post(() -> mWindow.show(p));
         }
 
@@ -398,6 +407,7 @@
             }
             return false;
         }
+
     }
 
     public void dump(PrintWriter pw, String prefix) {
@@ -408,5 +418,21 @@
         pw.print(prefix); pw.print("mContentWidth: "); pw.println(mContentWidth);
         pw.print(prefix); pw.print("mContentHeight: "); pw.println(mContentHeight);
         pw.print(prefix); pw.print("mDestroyed: "); pw.println(mDestroyed);
+        pw.print(prefix); pw.print("mWindow: ");
+        if (mWindow == null) {
+            pw.println("N/A");
+        } else {
+            final String prefix2 = prefix + "  ";
+            pw.println();
+            pw.print(prefix2); pw.print("showing: "); pw.println(mWindow.mShowing);
+            pw.print(prefix2); pw.print("view: "); pw.println(mWindow.mContentView);
+            pw.print(prefix2); pw.print("screen coordinates: ");
+            if (mWindow.mContentView == null) {
+                pw.println("N/A");
+            } else {
+                final int[] coordinates = mWindow.mContentView.getLocationOnScreen();
+                pw.print(coordinates[0]); pw.print("x"); pw.println(coordinates[1]);
+            }
+        }
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index bcdb118..d25ffce 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -37,6 +37,8 @@
 import com.android.internal.R;
 import com.android.server.UiThread;
 
+import java.io.PrintWriter;
+
 /**
  * Autofill Save Prompt
  */
@@ -96,6 +98,9 @@
 
     private final @NonNull OneTimeListener mListener;
 
+    private final CharSequence mTitle;
+    private final CharSequence mSubTitle;
+
     private boolean mDestroyed;
 
     SaveUi(@NonNull Context context, @NonNull CharSequence providerLabel, @NonNull SaveInfo info,
@@ -126,37 +131,36 @@
             types.add(context.getString(R.string.autofill_save_type_email_address));
         }
 
-        final CharSequence title;
         switch (types.size()) {
             case 1:
-                title = Html.fromHtml(context.getString(R.string.autofill_save_title_with_type,
+                mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_type,
                         types.valueAt(0), providerLabel), 0);
                 break;
             case 2:
-                title = Html.fromHtml(context.getString(R.string.autofill_save_title_with_2types,
+                mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_2types,
                         types.valueAt(0), types.valueAt(1), providerLabel), 0);
                 break;
             case 3:
-                title = Html.fromHtml(context.getString(R.string.autofill_save_title_with_3types,
+                mTitle = Html.fromHtml(context.getString(R.string.autofill_save_title_with_3types,
                         types.valueAt(0), types.valueAt(1), types.valueAt(2), providerLabel), 0);
                 break;
             default:
                 // Use generic if more than 3 or invalid type (size 0).
-                title = Html.fromHtml(
+                mTitle = Html.fromHtml(
                         context.getString(R.string.autofill_save_title, providerLabel), 0);
         }
 
-        titleView.setText(title);
-        final CharSequence subTitle = info.getDescription();
-        if (subTitle != null) {
+        titleView.setText(mTitle);
+        mSubTitle = info.getDescription();
+        if (mSubTitle != null) {
             final TextView subTitleView = (TextView) view.findViewById(R.id.autofill_save_subtitle);
-            subTitleView.setText(subTitle);
+            subTitleView.setText(mSubTitle);
             subTitleView.setVisibility(View.VISIBLE);
         }
 
-        Slog.i(TAG, "Showing save dialog: " + title);
+        Slog.i(TAG, "Showing save dialog: " + mTitle);
         if (sDebug) {
-            Slog.d(TAG, "SubTitle: " + subTitle);
+            Slog.d(TAG, "SubTitle: " + mSubTitle);
         }
 
         final TextView noButton = view.findViewById(R.id.autofill_save_no);
@@ -207,4 +211,18 @@
             throw new IllegalStateException("cannot interact with a destroyed instance");
         }
     }
+
+    void dump(PrintWriter pw, String prefix) {
+        pw.print(prefix); pw.print("title: "); pw.println(mTitle);
+        pw.print(prefix); pw.print("subtitle: "); pw.println(mSubTitle);
+
+        final View view = mDialog.getWindow().getDecorView();
+        final int[] loc = view.getLocationOnScreen();
+        pw.print(prefix); pw.print("coordinates: ");
+            pw.print('('); pw.print(loc[0]); pw.print(','); pw.print(loc[1]);pw.print(')');
+            pw.print('(');
+                pw.print(loc[0] + view.getWidth()); pw.print(',');
+                pw.print(loc[1] + view.getHeight());pw.println(')');
+        pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
+    }
 }
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index dd0b33d..1e74c55 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -776,7 +776,7 @@
     }
 
     // High level policy: apps are generally ineligible for backup if certain conditions apply
-    public static boolean appIsEligibleForBackup(ApplicationInfo app) {
+    public static boolean appIsEligibleForBackup(ApplicationInfo app, PackageManager pm) {
         // 1. their manifest states android:allowBackup="false"
         if ((app.flags&ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
             return false;
@@ -792,15 +792,18 @@
             return false;
         }
 
-        return true;
+        // Everything else checks out; the only remaining roadblock would be if the
+        // package were disabled
+        return !appIsDisabled(app, pm);
     }
 
-    // Checks if the app is in a stopped state, that means it won't receive broadcasts.
+    // Checks if the app is in a stopped state.  This is not part of the general "eligible for
+    // backup?" check because we *do* still need to restore data to apps in this state (e.g.
+    // newly-installing ones)
     private static boolean appIsStopped(ApplicationInfo app) {
         return ((app.flags & ApplicationInfo.FLAG_STOPPED) != 0);
     }
 
-    // We also avoid backups of 'disabled' apps
     private static boolean appIsDisabled(ApplicationInfo app, PackageManager pm) {
         switch (pm.getApplicationEnabledSetting(app.packageName)) {
             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
@@ -1528,7 +1531,8 @@
                     foundApps.add(pkgName); // all apps that we've addressed already
                     try {
                         PackageInfo pkg = mPackageManager.getPackageInfo(pkgName, 0);
-                        if (appGetsFullBackup(pkg) && appIsEligibleForBackup(pkg.applicationInfo)) {
+                        if (appGetsFullBackup(pkg)
+                                && appIsEligibleForBackup(pkg.applicationInfo, mPackageManager)) {
                             schedule.add(new FullBackupEntry(pkgName, lastBackup));
                         } else {
                             if (DEBUG) {
@@ -1547,7 +1551,8 @@
                 // New apps can arrive "out of band" via OTA and similar, so we also need to
                 // scan to make sure that we're tracking all full-backup candidates properly
                 for (PackageInfo app : apps) {
-                    if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
+                    if (appGetsFullBackup(app)
+                            && appIsEligibleForBackup(app.applicationInfo, mPackageManager)) {
                         if (!foundApps.contains(app.packageName)) {
                             if (MORE_DEBUG) {
                                 Slog.i(TAG, "New full backup app " + app.packageName + " found");
@@ -1576,7 +1581,8 @@
             changed = true;
             schedule = new ArrayList<FullBackupEntry>(apps.size());
             for (PackageInfo info : apps) {
-                if (appGetsFullBackup(info) && appIsEligibleForBackup(info.applicationInfo)) {
+                if (appGetsFullBackup(info)
+                        && appIsEligibleForBackup(info.applicationInfo, mPackageManager)) {
                     schedule.add(new FullBackupEntry(info.packageName, 0));
                 }
             }
@@ -2036,7 +2042,8 @@
                 for (String packageName : pkgList) {
                     try {
                         PackageInfo app = mPackageManager.getPackageInfo(packageName, 0);
-                        if (appGetsFullBackup(app) && appIsEligibleForBackup(app.applicationInfo)) {
+                        if (appGetsFullBackup(app)
+                                && appIsEligibleForBackup(app.applicationInfo, mPackageManager)) {
                             enqueueFullBackup(packageName, now);
                             scheduleNextFullBackupJob(0);
                         } else {
@@ -2440,7 +2447,7 @@
             try {
                 PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
                         PackageManager.GET_SIGNATURES);
-                if (!appIsEligibleForBackup(packageInfo.applicationInfo)) {
+                if (!appIsEligibleForBackup(packageInfo.applicationInfo, mPackageManager)) {
                     sendBackupOnPackageResult(observer, packageName,
                             BackupManager.ERROR_BACKUP_NOT_ALLOWED);
                     continue;
@@ -2949,7 +2956,7 @@
             try {
                 mCurrentPackage = mPackageManager.getPackageInfo(request.packageName,
                         PackageManager.GET_SIGNATURES);
-                if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo)) {
+                if (!appIsEligibleForBackup(mCurrentPackage.applicationInfo, mPackageManager)) {
                     // The manifest has changed but we had a stale backup request pending.
                     // This won't happen again because the app won't be requesting further
                     // backups.
@@ -4397,7 +4404,7 @@
             Iterator<Entry<String, PackageInfo>> iter = packagesToBackup.entrySet().iterator();
             while (iter.hasNext()) {
                 PackageInfo pkg = iter.next().getValue();
-                if (!appIsEligibleForBackup(pkg.applicationInfo)
+                if (!appIsEligibleForBackup(pkg.applicationInfo, mPackageManager)
                         || appIsStopped(pkg.applicationInfo)) {
                     iter.remove();
                     if (DEBUG) {
@@ -4679,7 +4686,7 @@
                     PackageInfo info = mPackageManager.getPackageInfo(pkg,
                             PackageManager.GET_SIGNATURES);
                     mCurrentPackage = info;
-                    if (!appIsEligibleForBackup(info.applicationInfo)) {
+                    if (!appIsEligibleForBackup(info.applicationInfo, mPackageManager)) {
                         // Cull any packages that have indicated that backups are not permitted,
                         // that run as system-domain uids but do not define their own backup agents,
                         // as well as any explicit mention of the 'special' shared-storage agent
@@ -8634,7 +8641,7 @@
                             continue;
                         }
 
-                        if (appIsEligibleForBackup(info.applicationInfo)) {
+                        if (appIsEligibleForBackup(info.applicationInfo, mPackageManager)) {
                             mAcceptSet.add(info);
                         }
                     } catch (NameNotFoundException e) {
@@ -10833,9 +10840,8 @@
         try {
             PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName,
                     PackageManager.GET_SIGNATURES);
-            if (!appIsEligibleForBackup(packageInfo.applicationInfo) ||
-                    appIsStopped(packageInfo.applicationInfo) ||
-                    appIsDisabled(packageInfo.applicationInfo, mPackageManager)) {
+            if (!appIsEligibleForBackup(packageInfo.applicationInfo, mPackageManager) ||
+                    appIsStopped(packageInfo.applicationInfo)) {
                 return false;
             }
             IBackupTransport transport = mTransportManager.getCurrentTransportBinder();
diff --git a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
index 92f00b8..8d91e0d 100644
--- a/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
+++ b/services/backup/java/com/android/server/backup/PackageManagerBackupAgent.java
@@ -140,7 +140,7 @@
         int N = pkgs.size();
         for (int a = N-1; a >= 0; a--) {
             PackageInfo pkg = pkgs.get(a);
-            if (!BackupManagerService.appIsEligibleForBackup(pkg.applicationInfo)) {
+            if (!BackupManagerService.appIsEligibleForBackup(pkg.applicationInfo, pm)) {
                 pkgs.remove(a);
             }
         }
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 1e56e95..9e7a29e 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -357,7 +357,13 @@
         if (svc != null) {
             svc.selectBackupTransportAsync(transport, listener);
         } else {
-            listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+            if (listener != null) {
+                try {
+                    listener.onFailure(BackupManager.ERROR_BACKUP_NOT_ALLOWED);
+                } catch (RemoteException ex) {
+                    // ignore
+                }
+            }
         }
     }
 
diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
index 20f7b12..03862c4 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
@@ -91,6 +91,7 @@
     /**
      * Old style: directly match the stored vs on device signature blocks.
      */
+    // TODO(b/37977154): Resolve questionable policies.
     public static boolean signaturesMatch(Signature[] storedSigs, PackageInfo target) {
         if (target == null) {
             return false;
@@ -110,7 +111,7 @@
         }
 
         // Allow unsigned apps, but not signed on one device and unsigned on the other
-        // !!! TODO: is this the right policy?
+        // TODO(b/37977154): is this the right policy?
         Signature[] deviceSigs = target.signatures;
         if (RefactoredBackupManagerService.MORE_DEBUG) {
             Slog.v(RefactoredBackupManagerService.TAG, "signaturesMatch(): stored=" + storedSigs
@@ -120,11 +121,12 @@
                 && (deviceSigs == null || deviceSigs.length == 0)) {
             return true;
         }
+        // TODO(b/37977154): This allows empty stored signature, is this right?
         if (storedSigs == null || deviceSigs == null) {
             return false;
         }
 
-        // !!! TODO: this demands that every stored signature match one
+        // TODO(b/37977154): this demands that every stored signature match one
         // that is present on device, and does not demand the converse.
         // Is this this right policy?
         int nStored = storedSigs.length;
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 42ea713..20a699b 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -13,7 +13,6 @@
     ../../../../system/netd/server/binder/android/net/INetd.aidl \
     ../../../../system/netd/server/binder/android/net/metrics/INetdEventListener.aidl \
     ../../../native/cmds/installd/binder/android/os/IInstalld.aidl \
-    ../../../native/services/vr/vr_window_manager/aidl/android/service/vr/IVrWindowManager.aidl \
 
 LOCAL_AIDL_INCLUDES += \
     system/netd/server/binder
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 6597a5e..a86612e 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1086,6 +1086,7 @@
         if (timeZoneWasChanged) {
             Intent intent = new Intent(Intent.ACTION_TIMEZONE_CHANGED);
             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING
+                    | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND
                     | Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
             intent.putExtra("time-zone", zone.getID());
             getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index 114d761..fdc0bba 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -631,6 +631,11 @@
                  PackageManager.PERMISSION_GRANTED;
     }
 
+    private boolean callerCanScoreNetworks() {
+        return mContext.checkCallingOrSelfPermission(permission.SCORE_NETWORKS) ==
+                PackageManager.PERMISSION_GRANTED;
+    }
+
     @Override
     public boolean clearScores() {
         // Only the active scorer or the system should be allowed to flush all scores.
@@ -651,9 +656,9 @@
     @Override
     public boolean setActiveScorer(String packageName) {
         // Only the system can set the active scorer
-        if (!isCallerSystemProcess(getCallingUid()) && !callerCanRequestScores()) {
+        if (!isCallerSystemProcess(getCallingUid()) && !callerCanScoreNetworks()) {
             throw new SecurityException(
-                    "Caller is neither the system process nor a score requester.");
+                    "Caller is neither the system process or a network scorer.");
         }
 
         return mNetworkScorerAppManager.setActiveScorer(packageName);
diff --git a/services/core/java/com/android/server/NetworkScorerAppManager.java b/services/core/java/com/android/server/NetworkScorerAppManager.java
index 8404025..42777bf 100644
--- a/services/core/java/com/android/server/NetworkScorerAppManager.java
+++ b/services/core/java/com/android/server/NetworkScorerAppManager.java
@@ -208,11 +208,11 @@
      *
      * <p>The caller must have permission to write to {@link Settings.Global}.
      *
-     * @param packageName the packageName of the new scorer to use. If null, the scoring app will
-     *                    revert back to the configured default. Otherwise, the scorer will only
-     *                    be set if it is a valid scorer application.
-     * @return true if the scorer was changed, or false if the package is not a valid scorer or
-     *         a valid network recommendation provider exists.
+     * @param packageName the packageName of the new scorer to use. If null, scoring will be forced
+     *                    off, otherwise the scorer will only be set if it is a valid scorer
+     *                    application.
+     * @return true if the package was a valid scorer (including <code>null</code>) and now
+     *         represents the active scorer, false otherwise.
      */
     @VisibleForTesting
     public boolean setActiveScorer(String packageName) {
@@ -223,16 +223,19 @@
             return true;
         }
 
-        if (packageName == null) {
-            // revert to the default setting.
-            packageName = getDefaultPackageSetting();
+        if (TextUtils.isEmpty(packageName)) {
+            Log.i(TAG, "Network scorer forced off, was: " + oldPackageName);
+            setNetworkRecommendationsPackage(null);
+            setNetworkRecommendationsEnabledSetting(
+                    NetworkScoreManager.RECOMMENDATIONS_ENABLED_FORCED_OFF);
+            return true;
         }
 
-        Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);
-
         // We only make the change if the new package is valid.
         if (getScorer(packageName) != null) {
+            Log.i(TAG, "Changing network scorer from " + oldPackageName + " to " + packageName);
             setNetworkRecommendationsPackage(packageName);
+            setNetworkRecommendationsEnabledSetting(NetworkScoreManager.RECOMMENDATIONS_ENABLED_ON);
             return true;
         } else {
             Log.w(TAG, "Requested network scorer is not valid: " + packageName);
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 4ce76f4..e609bd7 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -157,10 +157,6 @@
 
     private int[] mDataConnectionState;
 
-    private boolean[] mDataConnectionPossible;
-
-    private String[] mDataConnectionReason;
-
     private ArrayList<String>[] mConnectedApns;
 
     private LinkProperties[] mDataConnectionLinkProperties;
@@ -310,8 +306,6 @@
         mDataActivationState = new int[numPhones];
         mSignalStrength = new SignalStrength[numPhones];
         mMessageWaiting = new boolean[numPhones];
-        mDataConnectionPossible = new boolean[numPhones];
-        mDataConnectionReason = new String[numPhones];
         mCallForwarding = new boolean[numPhones];
         mCellLocation = new Bundle[numPhones];
         mDataConnectionLinkProperties = new LinkProperties[numPhones];
@@ -328,8 +322,6 @@
             mSignalStrength[i] =  new SignalStrength();
             mMessageWaiting[i] =  false;
             mCallForwarding[i] =  false;
-            mDataConnectionPossible[i] = false;
-            mDataConnectionReason[i] =  "";
             mCellLocation[i] = new Bundle();
             mCellInfo.add(i, null);
             mConnectedApns[i] = new ArrayList<String>();
@@ -1080,16 +1072,16 @@
         }
     }
 
-    public void notifyDataConnection(int state, boolean isDataConnectivityPossible,
+    public void notifyDataConnection(int state, boolean isDataAllowed,
             String reason, String apn, String apnType, LinkProperties linkProperties,
             NetworkCapabilities networkCapabilities, int networkType, boolean roaming) {
         notifyDataConnectionForSubscriber(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, state,
-            isDataConnectivityPossible,reason, apn, apnType, linkProperties,
+            isDataAllowed,reason, apn, apnType, linkProperties,
             networkCapabilities, networkType, roaming);
     }
 
     public void notifyDataConnectionForSubscriber(int subId, int state,
-            boolean isDataConnectivityPossible, String reason, String apn, String apnType,
+            boolean isDataAllowed, String reason, String apn, String apnType,
             LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
             int networkType, boolean roaming) {
         if (!checkNotifyPermission("notifyDataConnection()" )) {
@@ -1097,7 +1089,7 @@
         }
         if (VDBG) {
             log("notifyDataConnectionForSubscriber: subId=" + subId
-                + " state=" + state + " isDataConnectivityPossible=" + isDataConnectivityPossible
+                + " state=" + state + " isDataAllowed=" + isDataAllowed
                 + " reason='" + reason
                 + "' apn='" + apn + "' apnType=" + apnType + " networkType=" + networkType
                 + " mRecords.size()=" + mRecords.size());
@@ -1125,8 +1117,6 @@
                         }
                     }
                 }
-                mDataConnectionPossible[phoneId] = isDataConnectivityPossible;
-                mDataConnectionReason[phoneId] = reason;
                 mDataConnectionLinkProperties[phoneId] = linkProperties;
                 mDataConnectionNetworkCapabilities[phoneId] = networkCapabilities;
                 if (mDataConnectionNetworkType[phoneId] != networkType) {
@@ -1173,7 +1163,7 @@
             }
             handleRemoveListLocked();
         }
-        broadcastDataConnectionStateChanged(state, isDataConnectivityPossible, reason, apn,
+        broadcastDataConnectionStateChanged(state, isDataAllowed, reason, apn,
                 apnType, linkProperties, networkCapabilities, roaming, subId);
         broadcastPreciseDataConnectionStateChanged(state, networkType, apnType, apn, reason,
                 linkProperties, "");
@@ -1414,8 +1404,6 @@
                 pw.println("mCallForwarding=" + mCallForwarding[i]);
                 pw.println("mDataActivity=" + mDataActivity[i]);
                 pw.println("mDataConnectionState=" + mDataConnectionState[i]);
-                pw.println("mDataConnectionPossible=" + mDataConnectionPossible[i]);
-                pw.println("mDataConnectionReason=" + mDataConnectionReason[i]);
                 pw.println("mDataConnectionLinkProperties=" + mDataConnectionLinkProperties[i]);
                 pw.println("mDataConnectionNetworkCapabilities=" +
                         mDataConnectionNetworkCapabilities[i]);
@@ -1544,7 +1532,7 @@
     }
 
     private void broadcastDataConnectionStateChanged(int state,
-            boolean isDataConnectivityPossible,
+            boolean isDataAllowed,
             String reason, String apn, String apnType, LinkProperties linkProperties,
             NetworkCapabilities networkCapabilities, boolean roaming, int subId) {
         // Note: not reporting to the battery stats service here, because the
@@ -1553,7 +1541,7 @@
         Intent intent = new Intent(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
         intent.putExtra(PhoneConstants.STATE_KEY,
                 PhoneConstantConversions.convertDataState(state).toString());
-        if (!isDataConnectivityPossible) {
+        if (!isDataAllowed) {
             intent.putExtra(PhoneConstants.NETWORK_UNAVAILABLE_KEY, true);
         }
         if (reason != null) {
diff --git a/services/core/java/com/android/server/vr/CompatibilityDisplay.java b/services/core/java/com/android/server/Vr2dDisplay.java
similarity index 93%
rename from services/core/java/com/android/server/vr/CompatibilityDisplay.java
rename to services/core/java/com/android/server/Vr2dDisplay.java
index d7cdf08..1116e4e 100644
--- a/services/core/java/com/android/server/vr/CompatibilityDisplay.java
+++ b/services/core/java/com/android/server/Vr2dDisplay.java
@@ -3,7 +3,7 @@
 import static android.view.Display.INVALID_DISPLAY;
 
 import android.app.ActivityManagerInternal;
-import android.app.CompatibilityDisplayProperties;
+import android.app.Vr2dDisplayProperties;
 import android.app.Service;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -31,8 +31,8 @@
  * Creates a 2D Virtual Display while VR Mode is enabled. This display will be used to run and
  * render 2D app within a VR experience. For example, bringing up the 2D calculator app in VR.
  */
-class CompatibilityDisplay {
-    private final static String TAG = "CompatDisplay";
+class Vr2dDisplay {
+    private final static String TAG = "Vr2dDisplay";
     private final static boolean DEBUG = false;
 
     // TODO: Go over these values and figure out what is best
@@ -42,13 +42,13 @@
     private final static int STOP_VIRTUAL_DISPLAY_DELAY_MILLIS = 2000;
 
     private final static String DEBUG_ACTION_SET_MODE =
-            "com.android.server.vr.CompatibilityDisplay.SET_MODE";
+            "com.android.server.vr.Vr2dDisplay.SET_MODE";
     private final static String DEBUG_EXTRA_MODE_ON =
-            "com.android.server.vr.CompatibilityDisplay.EXTRA_MODE_ON";
+            "com.android.server.vr.Vr2dDisplay.EXTRA_MODE_ON";
     private final static String DEBUG_ACTION_SET_SURFACE =
-            "com.android.server.vr.CompatibilityDisplay.SET_SURFACE";
+            "com.android.server.vr.Vr2dDisplay.SET_SURFACE";
     private final static String DEBUG_EXTRA_SURFACE =
-            "com.android.server.vr.CompatibilityDisplay.EXTRA_SURFACE";
+            "com.android.server.vr.Vr2dDisplay.EXTRA_SURFACE";
 
     /**
      * The default width of the VR virtual display
@@ -99,7 +99,7 @@
     private boolean mIsVrModeOverrideEnabled;
     private boolean mIsVrModeEnabled;
 
-    public CompatibilityDisplay(DisplayManager displayManager,
+    public Vr2dDisplay(DisplayManager displayManager,
            ActivityManagerInternal activityManagerInternal, IVrManager vrManager) {
         mDisplayManager = displayManager;
         mActivityManagerInternal = activityManagerInternal;
@@ -190,7 +190,7 @@
     }
 
     /**
-     * Sets the resolution and DPI of the compatibility virtual display used to display
+     * Sets the resolution and DPI of the Vr2d virtual display used to display
      * 2D applications in VR mode.
      *
      * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
@@ -198,7 +198,7 @@
      * @param compatDisplayProperties Properties of the virtual display for 2D applications
      * in VR mode.
      */
-    public void setVirtualDisplayProperties(CompatibilityDisplayProperties compatDisplayProperties) {
+    public void setVirtualDisplayProperties(Vr2dDisplayProperties compatDisplayProperties) {
         synchronized(mVdLock) {
             if (DEBUG) {
                 Log.i(TAG, "VD setVirtualDisplayProperties: res = " +
@@ -273,13 +273,13 @@
                     null /* Surface */, 0 /* flags */);
 
             if (mVirtualDisplay != null) {
-                mActivityManagerInternal.setVrCompatibilityDisplayId(
+                mActivityManagerInternal.setVr2dDisplayId(
                     mVirtualDisplay.getDisplay().getDisplayId());
                 // Now create the ImageReader to supply a Surface to the new virtual display.
                 startImageReader();
             } else {
                 Log.w(TAG, "Virtual display id is null after createVirtualDisplay");
-                mActivityManagerInternal.setVrCompatibilityDisplayId(INVALID_DISPLAY);
+                mActivityManagerInternal.setVr2dDisplayId(INVALID_DISPLAY);
                 return;
             }
         }
@@ -302,7 +302,7 @@
                     } else {
                         Log.i(TAG, "Stopping Virtual Display");
                         synchronized (mVdLock) {
-                            mActivityManagerInternal.setVrCompatibilityDisplayId(INVALID_DISPLAY);
+                            mActivityManagerInternal.setVr2dDisplayId(INVALID_DISPLAY);
                             setSurfaceLocked(null); // clean up and release the surface first.
                             if (mVirtualDisplay != null) {
                                 mVirtualDisplay.release();
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index e0fc531..1ed46a0 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -166,8 +166,11 @@
      */
     static final class ActiveForegroundApp {
         String mPackageName;
+        int mUid;
         CharSequence mLabel;
         boolean mShownWhileScreenOn;
+        boolean mAppOnTop;
+        boolean mShownWhileTop;
         long mStartTime;
         long mStartVisibleTime;
         long mEndTime;
@@ -619,6 +622,17 @@
                             != ActivityManager.APP_START_MODE_NORMAL) {
                         if (stopping == null) {
                             stopping = new ArrayList<>();
+                            String compName = service.name.flattenToShortString();
+                            EventLogTags.writeAmStopIdleService(service.appInfo.uid, compName);
+                            StringBuilder sb = new StringBuilder(64);
+                            sb.append("Stopping service due to app idle: ");
+                            UserHandle.formatUid(sb, service.appInfo.uid);
+                            sb.append(" ");
+                            TimeUtils.formatDuration(service.createTime
+                                    - SystemClock.elapsedRealtime(), sb);
+                            sb.append(" ");
+                            sb.append(compName);
+                            Slog.w(TAG, sb.toString());
                             stopping.add(service);
                         }
                     }
@@ -728,11 +742,12 @@
         synchronized (mAm) {
             final long now = SystemClock.elapsedRealtime();
             final long nowPlusMin = now + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME;
+            long nextUpdateTime = Long.MAX_VALUE;
             if (smap != null) {
                 for (int i = smap.mActiveForegroundApps.size()-1; i >= 0; i--) {
                     ActiveForegroundApp aa = smap.mActiveForegroundApps.valueAt(i);
                     if (aa.mEndTime != 0 && (mScreenOn || aa.mShownWhileScreenOn)) {
-                        if (aa.mEndTime < (aa.mStartVisibleTime
+                        if (!aa.mShownWhileTop && aa.mEndTime < (aa.mStartVisibleTime
                                 + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) {
                             // Check to see if this should still be displayed...  we continue
                             // until it has been shown for at least the timeout duration.
@@ -741,6 +756,12 @@
                                 smap.mActiveForegroundApps.removeAt(i);
                                 smap.mActiveForegroundAppsChanged = true;
                                 continue;
+                            } else {
+                                long hideTime = aa.mStartVisibleTime
+                                        + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME;
+                                if (hideTime < nextUpdateTime) {
+                                    nextUpdateTime = hideTime;
+                                }
                             }
                         } else {
                             // This was up for longer than the timeout, so just remove immediately.
@@ -749,10 +770,17 @@
                             continue;
                         }
                     }
-                    if (active == null) {
-                        active = new ArrayList<>();
+                    if (!aa.mAppOnTop) {
+                        if (active == null) {
+                            active = new ArrayList<>();
+                        }
+                        active.add(aa);
                     }
-                    active.add(aa);
+                }
+                smap.removeMessages(ServiceMap.MSG_UPDATE_FOREGROUND_APPS);
+                if (nextUpdateTime < Long.MAX_VALUE) {
+                    Message msg = smap.obtainMessage();
+                    smap.sendMessageAtTime(msg, nextUpdateTime);
                 }
             }
             if (!smap.mActiveForegroundAppsChanged) {
@@ -842,7 +870,7 @@
             active.mNumActive--;
             if (active.mNumActive <= 0) {
                 active.mEndTime = SystemClock.elapsedRealtime();
-                if (active.mEndTime >= (active.mStartVisibleTime
+                if (active.mShownWhileTop || active.mEndTime >= (active.mStartVisibleTime
                         + mAm.mConstants.FOREGROUND_SERVICE_UI_MIN_TIME)) {
                     // Have been active for long enough that we will remove it immediately.
                     smap.mActiveForegroundApps.remove(r.packageName);
@@ -887,6 +915,31 @@
         }
     }
 
+    void foregroundServiceProcStateChangedLocked(UidRecord uidRec) {
+        ServiceMap smap = mServiceMap.get(UserHandle.getUserId(uidRec.uid));
+        if (smap != null) {
+            boolean changed = false;
+            for (int j = smap.mActiveForegroundApps.size()-1; j >= 0; j--) {
+                ActiveForegroundApp active = smap.mActiveForegroundApps.valueAt(j);
+                if (active.mUid == uidRec.uid) {
+                    if (uidRec.curProcState <= ActivityManager.PROCESS_STATE_TOP) {
+                        if (!active.mAppOnTop) {
+                            active.mAppOnTop = true;
+                            changed = true;
+                        }
+                        active.mShownWhileTop = true;
+                    } else if (active.mAppOnTop) {
+                        active.mAppOnTop = false;
+                        changed = true;
+                    }
+                }
+            }
+            if (changed) {
+                requestUpdateActiveForegroundAppsLocked(smap, 0);
+            }
+        }
+    }
+
     private void setServiceForegroundInnerLocked(ServiceRecord r, int id,
             Notification notification, int flags) {
         if (id != 0) {
@@ -948,7 +1001,13 @@
                     if (active == null) {
                         active = new ActiveForegroundApp();
                         active.mPackageName = r.packageName;
+                        active.mUid = r.appInfo.uid;
                         active.mShownWhileScreenOn = mScreenOn;
+                        if (r.app != null) {
+                            active.mAppOnTop = active.mShownWhileTop =
+                                    r.app.uidRecord.curProcState
+                                            <= ActivityManager.PROCESS_STATE_TOP;
+                        }
                         active.mStartTime = active.mStartVisibleTime
                                 = SystemClock.elapsedRealtime();
                         smap.mActiveForegroundApps.put(r.packageName, active);
@@ -1258,6 +1317,10 @@
 
             mAm.startAssociationLocked(callerApp.uid, callerApp.processName, callerApp.curProcState,
                     s.appInfo.uid, s.name, s.processName);
+            // Once the apps have become associated, if one of them is caller is ephemeral
+            // the target app should now be able to see the calling app
+            mAm.grantEphemeralAccessLocked(callerApp.userId, service,
+                    s.appInfo.uid, UserHandle.getAppId(callerApp.uid));
 
             AppBindRecord b = s.retrieveAppBindingLocked(service, callerApp);
             ConnectionRecord c = new ConnectionRecord(b, activity,
@@ -1312,7 +1375,7 @@
                 // This could have made the service more important.
                 mAm.updateLruProcessLocked(s.app, s.app.hasClientActivities
                         || s.app.treatLikeActivity, b.client);
-                mAm.updateOomAdjLocked(s.app);
+                mAm.updateOomAdjLocked(s.app, true);
             }
 
             if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
@@ -1427,13 +1490,15 @@
                                 r.binding.service.app.hasClientActivities
                                 || r.binding.service.app.treatLikeActivity, null);
                     }
-                    mAm.updateOomAdjLocked(r.binding.service.app);
+                    mAm.updateOomAdjLocked(r.binding.service.app, false);
                 }
             }
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
 
+        mAm.updateOomAdjLocked();
+
         return true;
     }
 
@@ -2173,7 +2238,7 @@
             bumpServiceExecutingLocked(r, execInFg, "start");
             if (!oomAdjusted) {
                 oomAdjusted = true;
-                mAm.updateOomAdjLocked(r.app);
+                mAm.updateOomAdjLocked(r.app, true);
             }
             if (r.fgRequired && !r.fgWaiting) {
                 if (!r.isForeground) {
@@ -2297,7 +2362,7 @@
                 if (ibr.hasBound) {
                     try {
                         bumpServiceExecutingLocked(r, false, "bring down unbind");
-                        mAm.updateOomAdjLocked(r.app);
+                        mAm.updateOomAdjLocked(r.app, true);
                         ibr.hasBound = false;
                         ibr.requested = false;
                         r.app.thread.scheduleUnbindService(r,
@@ -2389,7 +2454,7 @@
                     bumpServiceExecutingLocked(r, false, "destroy");
                     mDestroyingServices.add(r);
                     r.destroying = true;
-                    mAm.updateOomAdjLocked(r.app);
+                    mAm.updateOomAdjLocked(r.app, true);
                     r.app.thread.scheduleStopService(r);
                 } catch (Exception e) {
                     Slog.w(TAG, "Exception when destroying service "
@@ -2490,7 +2555,7 @@
                         // it to go down there and we want it to start out near the top.
                         mAm.updateLruProcessLocked(s.app, false, null);
                     }
-                    mAm.updateOomAdjLocked(s.app);
+                    mAm.updateOomAdjLocked(s.app, true);
                     b.intent.hasBound = false;
                     // Assume the client doesn't want to know about a rebind;
                     // we will deal with that later if it asks for one.
@@ -2643,7 +2708,7 @@
                     mDestroyingServices.remove(r);
                     r.bindings.clear();
                 }
-                mAm.updateOomAdjLocked(r.app);
+                mAm.updateOomAdjLocked(r.app, true);
             }
             r.executeFg = false;
             if (r.tracker != null) {
@@ -2786,6 +2851,9 @@
                 if (!doit && didSomething) {
                     return true;
                 }
+                if (doit && filterByClasses == null) {
+                    forceStopPackageLocked(packageName, mServiceMap.valueAt(i).mUserId);
+                }
             }
         } else {
             ServiceMap smap = mServiceMap.get(userId);
@@ -2794,6 +2862,9 @@
                 didSomething = collectPackageServicesLocked(packageName, filterByClasses,
                         evenPersistent, doit, killProcess, items);
             }
+            if (doit && filterByClasses == null) {
+                forceStopPackageLocked(packageName, userId);
+            }
         }
 
         if (mTmpCollectionResults != null) {
@@ -2802,10 +2873,11 @@
             }
             mTmpCollectionResults.clear();
         }
+
         return didSomething;
     }
 
-    void removeUninstalledPackageLocked(String packageName, int userId) {
+    void forceStopPackageLocked(String packageName, int userId) {
         ServiceMap smap = mServiceMap.get(userId);
         if (smap != null && smap.mActiveForegroundApps.size() > 0) {
             for (int i = smap.mActiveForegroundApps.size()-1; i >= 0; i--) {
@@ -3636,6 +3708,10 @@
                         }
                         pw.print("    mNumActive=");
                         pw.print(aa.mNumActive);
+                        pw.print(" mAppOnTop=");
+                        pw.print(aa.mAppOnTop);
+                        pw.print(" mShownWhileTop=");
+                        pw.print(aa.mShownWhileTop);
                         pw.print(" mShownWhileScreenOn=");
                         pw.println(aa.mShownWhileScreenOn);
                         pw.print("    mStartTime=");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index ace2b55..8afbaa5 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -120,7 +120,6 @@
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_POWER_QUICK;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESS_OBSERVERS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROVIDER;
@@ -572,11 +571,10 @@
     // Determines whether to take full screen screenshots
     static final boolean TAKE_FULLSCREEN_SCREENSHOTS = true;
 
-    // STOPSHIP: Update default to a smaller value.
     /**
      * Default value for {@link Settings.Global#NETWORK_ACCESS_TIMEOUT_MS}.
      */
-    private static final long NETWORK_ACCESS_TIMEOUT_DEFAULT_MS = 2000; // 2 sec
+    private static final long NETWORK_ACCESS_TIMEOUT_DEFAULT_MS = 200; // 0.2 sec
 
     /**
      * State indicating that there is no need for any blocking for network.
@@ -627,8 +625,8 @@
 
     private final VrController mVrController;
 
-    // VR Compatibility Display Id.
-    int mVrCompatibilityDisplayId = INVALID_DISPLAY;
+    // VR Vr2d Display Id.
+    int mVr2dDisplayId = INVALID_DISPLAY;
 
     // Whether we should use SCHED_FIFO for UI and RenderThreads.
     private boolean mUseFifoUiScheduling = false;
@@ -814,15 +812,28 @@
     final SparseArray<ProcessRecord> mPidsSelfLocked = new SparseArray<ProcessRecord>();
 
     /**
-     * All of the processes that have been forced to be foreground.  The key
+     * All of the processes that have been forced to be important.  The key
      * is the pid of the caller who requested it (we hold a death
      * link on it).
      */
-    abstract class ForegroundToken implements IBinder.DeathRecipient {
-        int pid;
-        IBinder token;
+    abstract class ImportanceToken implements IBinder.DeathRecipient {
+        final int pid;
+        final IBinder token;
+        final String reason;
+
+        ImportanceToken(int _pid, IBinder _token, String _reason) {
+            pid = _pid;
+            token = _token;
+            reason = _reason;
+        }
+
+        @Override
+        public String toString() {
+            return "ImportanceToken { " + Integer.toHexString(System.identityHashCode(this))
+                    + " " + reason + " " + pid + " " + token + " }";
+        }
     }
-    final SparseArray<ForegroundToken> mForegroundProcesses = new SparseArray<ForegroundToken>();
+    final SparseArray<ImportanceToken> mImportantProcesses = new SparseArray<ImportanceToken>();
 
     /**
      * List of records for processes that someone had tried to start before the
@@ -4312,6 +4323,7 @@
                         validateUid.idle = false;
                     }
                     validateUid.curProcState = validateUid.setProcState = item.processState;
+                    validateUid.lastDispatchedProcStateSeq = item.procStateSeq;
                 }
             }
         }
@@ -5407,7 +5419,7 @@
     public static class DumpStackFileObserver extends FileObserver {
         // Keep in sync with frameworks/native/cmds/dumpstate/utils.cpp
         private static final int TRACE_DUMP_TIMEOUT_MS = 10000; // 10 seconds
-        static final int TRACE_DUMP_TIMEOUT_SECONDS = TRACE_DUMP_TIMEOUT_MS / 1000;
+        static final int NATIVE_DUMP_TIMEOUT_MS = 2000; // 2 seconds;
 
         private final String mTracesPath;
         private boolean mClosed;
@@ -5423,21 +5435,41 @@
             notify();
         }
 
-        public void dumpWithTimeout(int pid) {
+        public long dumpWithTimeout(int pid, long timeout) {
             sendSignal(pid, SIGNAL_QUIT);
+            final long start = SystemClock.elapsedRealtime();
+
+            final long waitTime = Math.min(timeout, TRACE_DUMP_TIMEOUT_MS);
             synchronized (this) {
                 try {
-                    wait(TRACE_DUMP_TIMEOUT_MS); // Wait for traces file to be closed.
+                    wait(waitTime); // Wait for traces file to be closed.
                 } catch (InterruptedException e) {
                     Slog.wtf(TAG, e);
                 }
             }
+
+            // This avoids a corner case of passing a negative time to the native
+            // trace in case we've already hit the overall timeout.
+            final long timeWaited = SystemClock.elapsedRealtime() - start;
+            if (timeWaited >= timeout) {
+                return timeWaited;
+            }
+
             if (!mClosed) {
                 Slog.w(TAG, "Didn't see close of " + mTracesPath + " for pid " + pid +
                        ". Attempting native stack collection.");
-                Debug.dumpNativeBacktraceToFileTimeout(pid, mTracesPath, TRACE_DUMP_TIMEOUT_SECONDS);
+
+                final long nativeDumpTimeoutMs = Math.min(
+                        NATIVE_DUMP_TIMEOUT_MS, timeout - timeWaited);
+
+                Debug.dumpNativeBacktraceToFileTimeout(pid, mTracesPath,
+                        (int) (nativeDumpTimeoutMs / 1000));
             }
+
+            final long end = SystemClock.elapsedRealtime();
             mClosed = false;
+
+            return (end - start);
         }
     }
 
@@ -5447,6 +5479,9 @@
         // Use a FileObserver to detect when traces finish writing.
         // The order of traces is considered important to maintain for legibility.
         DumpStackFileObserver observer = new DumpStackFileObserver(tracesPath);
+
+        // We must complete all stack dumps within 20 seconds.
+        long remainingTime = 20 * 1000;
         try {
             observer.startWatching();
 
@@ -5456,10 +5491,18 @@
                 for (int i = 0; i < num; i++) {
                     if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
                             + firstPids.get(i));
-                    final long sime = SystemClock.elapsedRealtime();
-                    observer.dumpWithTimeout(firstPids.get(i));
-                    if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)
-                            + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
+                    final long timeTaken = observer.dumpWithTimeout(firstPids.get(i), remainingTime);
+
+                    remainingTime -= timeTaken;
+                    if (remainingTime <= 0) {
+                        Slog.e(TAG, "Aborting stack trace dump (current firstPid=" + firstPids.get(i) +
+                            "); deadline exceeded.");
+                        return;
+                    }
+
+                    if (DEBUG_ANR) {
+                        Slog.d(TAG, "Done with pid " + firstPids.get(i) + " in " + timeTaken + "ms");
+                    }
                 }
             }
 
@@ -5467,12 +5510,24 @@
             if (nativePids != null) {
                 for (int pid : nativePids) {
                     if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
-                    final long sime = SystemClock.elapsedRealtime();
+                    final long nativeDumpTimeoutMs = Math.min(
+                            DumpStackFileObserver.NATIVE_DUMP_TIMEOUT_MS, remainingTime);
 
+                    final long start = SystemClock.elapsedRealtime();
                     Debug.dumpNativeBacktraceToFileTimeout(
-                            pid, tracesPath, DumpStackFileObserver.TRACE_DUMP_TIMEOUT_SECONDS);
-                    if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
-                            + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
+                            pid, tracesPath, (int) (nativeDumpTimeoutMs / 1000));
+                    final long timeTaken = SystemClock.elapsedRealtime() - start;
+
+                    remainingTime -= timeTaken;
+                    if (remainingTime <= 0) {
+                        Slog.e(TAG, "Aborting stack trace dump (current native pid=" + pid +
+                            "); deadline exceeded.");
+                        return;
+                    }
+
+                    if (DEBUG_ANR) {
+                        Slog.d(TAG, "Done with native pid " + pid + " in " + timeTaken + "ms");
+                    }
                 }
             }
 
@@ -5496,12 +5551,20 @@
                     ProcessCpuTracker.Stats stats = processCpuTracker.getWorkingStats(i);
                     if (lastPids.indexOfKey(stats.pid) >= 0) {
                         numProcs++;
-                        if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid "
-                                + stats.pid);
-                        final long stime = SystemClock.elapsedRealtime();
-                        observer.dumpWithTimeout(stats.pid);
-                        if (DEBUG_ANR) Slog.d(TAG, "Done with extra pid " + stats.pid
-                                + " in " + (SystemClock.elapsedRealtime()-stime) + "ms");
+
+                        if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid " + stats.pid);
+
+                        final long timeTaken = observer.dumpWithTimeout(stats.pid, remainingTime);
+                        remainingTime -= timeTaken;
+                        if (remainingTime <= 0) {
+                            Slog.e(TAG, "Aborting stack trace dump (current extra pid=" + stats.pid +
+                                "); deadline exceeded.");
+                            return;
+                        }
+
+                        if (DEBUG_ANR) {
+                            Slog.d(TAG, "Done with extra pid " + stats.pid + " in " + timeTaken + "ms");
+                        }
                     } else if (DEBUG_ANR) {
                         Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "
                                 + stats.pid);
@@ -6429,6 +6492,7 @@
                 if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS,
                         "No more processes in " + old.uidRecord);
                 enqueueUidChangeLocked(old.uidRecord, -1, UidRecord.CHANGE_GONE);
+                EventLogTags.writeAmUidStopped(uid);
                 mActiveUids.remove(uid);
                 noteUidProcessState(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
             }
@@ -6460,6 +6524,7 @@
             }
             uidRec.updateHasInternetPermission();
             mActiveUids.put(proc.uid, uidRec);
+            EventLogTags.writeAmUidRunning(uidRec.uid);
             noteUidProcessState(uidRec.uid, uidRec.curProcState);
             enqueueUidChangeLocked(uidRec, -1, UidRecord.CHANGE_ACTIVE);
         }
@@ -6647,7 +6712,7 @@
         app.makeActive(thread, mProcessStats);
         app.curAdj = app.setAdj = app.verifiedAdj = ProcessList.INVALID_ADJ;
         app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-        app.forcingToForeground = null;
+        app.forcingToImportant = null;
         updateProcessForegroundLocked(app, false, false);
         app.hasShownUi = false;
         app.debugging = false;
@@ -6775,6 +6840,7 @@
             }
 
             checkTime(startTime, "attachApplicationLocked: immediately before bindApplication");
+            mStackSupervisor.mActivityMetricsLogger.notifyBindApplication(app);
             if (app.instr != null) {
                 thread.bindApplication(processName, appInfo, providers,
                         app.instr.mClass,
@@ -6859,7 +6925,7 @@
         }
 
         // Check whether the next backup agent is in this process...
-        if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
+        if (!badApp && mBackupTarget != null && mBackupTarget.app == app) {
             if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
                     "New app is backup target, launching agent for " + app);
             notifyPackageUse(mBackupTarget.appInfo.packageName,
@@ -7646,20 +7712,20 @@
         }
     }
 
-    void foregroundTokenDied(ForegroundToken token) {
+    void importanceTokenDied(ImportanceToken token) {
         synchronized (ActivityManagerService.this) {
             synchronized (mPidsSelfLocked) {
-                ForegroundToken cur
-                    = mForegroundProcesses.get(token.pid);
+                ImportanceToken cur
+                    = mImportantProcesses.get(token.pid);
                 if (cur != token) {
                     return;
                 }
-                mForegroundProcesses.remove(token.pid);
+                mImportantProcesses.remove(token.pid);
                 ProcessRecord pr = mPidsSelfLocked.get(token.pid);
                 if (pr == null) {
                     return;
                 }
-                pr.forcingToForeground = null;
+                pr.forcingToImportant = null;
                 updateProcessForegroundLocked(pr, false, false);
             }
             updateOomAdjLocked();
@@ -7667,9 +7733,9 @@
     }
 
     @Override
-    public void setProcessForeground(IBinder token, int pid, boolean isForeground) {
+    public void setProcessImportant(IBinder token, int pid, boolean isForeground, String reason) {
         enforceCallingPermission(android.Manifest.permission.SET_PROCESS_LIMIT,
-                "setProcessForeground()");
+                "setProcessImportant()");
         synchronized(this) {
             boolean changed = false;
 
@@ -7679,28 +7745,26 @@
                     Slog.w(TAG, "setProcessForeground called on unknown pid: " + pid);
                     return;
                 }
-                ForegroundToken oldToken = mForegroundProcesses.get(pid);
+                ImportanceToken oldToken = mImportantProcesses.get(pid);
                 if (oldToken != null) {
                     oldToken.token.unlinkToDeath(oldToken, 0);
-                    mForegroundProcesses.remove(pid);
+                    mImportantProcesses.remove(pid);
                     if (pr != null) {
-                        pr.forcingToForeground = null;
+                        pr.forcingToImportant = null;
                     }
                     changed = true;
                 }
                 if (isForeground && token != null) {
-                    ForegroundToken newToken = new ForegroundToken() {
+                    ImportanceToken newToken = new ImportanceToken(pid, token, reason) {
                         @Override
                         public void binderDied() {
-                            foregroundTokenDied(this);
+                            importanceTokenDied(this);
                         }
                     };
-                    newToken.pid = pid;
-                    newToken.token = token;
                     try {
                         token.linkToDeath(newToken, 0);
-                        mForegroundProcesses.put(pid, newToken);
-                        pr.forcingToForeground = token;
+                        mImportantProcesses.put(pid, newToken);
+                        pr.forcingToImportant = newToken;
                         changed = true;
                     } catch (RemoteException e) {
                         // If the process died while doing this, we will later
@@ -11242,7 +11306,7 @@
 
                 checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
                 final int verifiedAdj = cpr.proc.verifiedAdj;
-                boolean success = updateOomAdjLocked(cpr.proc);
+                boolean success = updateOomAdjLocked(cpr.proc, true);
                 // XXX things have changed so updateOomAdjLocked doesn't actually tell us
                 // if the process has been successfully adjusted.  So to reduce races with
                 // it, we will check whether the process still exists.  Note that this doesn't
@@ -11704,7 +11768,7 @@
                         dst.proc = r;
                         dst.notifyAll();
                     }
-                    updateOomAdjLocked(r);
+                    updateOomAdjLocked(r, true);
                     maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                             src.info.authority);
                 }
@@ -13429,7 +13493,7 @@
                     }
                 }
                 if (changed) {
-                    updateOomAdjLocked(pr);
+                    updateOomAdjLocked(pr, true);
                 }
             }
         } finally {
@@ -15414,12 +15478,12 @@
             }
         }
 
-        if (mForegroundProcesses.size() > 0) {
+        if (mImportantProcesses.size() > 0) {
             synchronized (mPidsSelfLocked) {
                 boolean printed = false;
-                for (int i=0; i<mForegroundProcesses.size(); i++) {
+                for (int i = 0; i< mImportantProcesses.size(); i++) {
                     ProcessRecord r = mPidsSelfLocked.get(
-                            mForegroundProcesses.valueAt(i).pid);
+                            mImportantProcesses.valueAt(i).pid);
                     if (dumpPackage != null && (r == null
                             || !r.pkgList.containsKey(dumpPackage))) {
                         continue;
@@ -15431,8 +15495,8 @@
                         printed = true;
                         printedAnything = true;
                     }
-                    pw.print("    PID #"); pw.print(mForegroundProcesses.keyAt(i));
-                            pw.print(": "); pw.println(mForegroundProcesses.valueAt(i));
+                    pw.print("    PID #"); pw.print(mImportantProcesses.keyAt(i));
+                            pw.print(": "); pw.println(mImportantProcesses.valueAt(i));
                 }
             }
         }
@@ -17703,7 +17767,7 @@
         app.unlinkDeathRecipient();
         app.makeInactive(mProcessStats);
         app.waitingToKill = null;
-        app.forcingToForeground = null;
+        app.forcingToImportant = null;
         updateProcessForegroundLocked(app, false, false);
         app.foregroundActivities = false;
         app.hasShownUi = false;
@@ -18203,7 +18267,7 @@
             mBackupAppName = app.packageName;
 
             // Try not to kill the process during backup
-            updateOomAdjLocked(proc);
+            updateOomAdjLocked(proc, true);
 
             // If the process is already attached, schedule the creation of the backup agent now.
             // If it is not yet live, this will be done when it attaches to the framework.
@@ -18300,7 +18364,7 @@
 
                 // Not backing this app up any more; reset its OOM adjustment
                 final ProcessRecord proc = mBackupTarget.app;
-                updateOomAdjLocked(proc);
+                updateOomAdjLocked(proc, true);
                 proc.inFullBackup = false;
 
                 oldBackupUid = mBackupTarget != null ? mBackupTarget.appInfo.uid : -1;
@@ -18982,7 +19046,7 @@
 
                                         removeTasksByPackageNameLocked(ssp, userId);
 
-                                        mServices.removeUninstalledPackageLocked(ssp, userId);
+                                        mServices.forceStopPackageLocked(ssp, userId);
 
                                         // Hide the "unsupported display" dialog if necessary.
                                         if (mUnsupportedDisplaySizeDialog != null && ssp.equals(
@@ -19865,8 +19929,9 @@
     }
 
     /**
-     * NOTE: For the pinned stack, this method is only called after the bounds animation has
-     *       animated the stack to the fullscreen.
+     * NOTE: For the pinned stack, this method is usually called after the bounds animation has
+     *       animated the stack to the fullscreen, but can also be called if we are relaunching an
+     *       activity and clearing the task at the same time.
      */
     @Override
     public void moveTasksToFullscreenStack(int fromStackId, boolean onTop) {
@@ -20697,14 +20762,6 @@
                 app.cached = false;
                 app.adjType = "fg-service";
                 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
-            } else if (app.forcingToForeground != null) {
-                // The user is aware of this app, so make it visible.
-                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
-                procState = ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
-                app.cached = false;
-                app.adjType = "force-fg";
-                app.adjSource = app.forcingToForeground;
-                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             } else if (app.hasOverlayUi) {
                 // The process is display an overlay UI.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
@@ -20715,6 +20772,21 @@
             }
         }
 
+        if (adj > ProcessList.PERCEPTIBLE_APP_ADJ
+                || procState > ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND) {
+            if (app.forcingToImportant != null) {
+                // This is currently used for toasts...  they are not interactive, and
+                // we don't want them to cause the app to become fully foreground (and
+                // thus out of background check), so we yes the best background level we can.
+                adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+                procState = ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+                app.cached = false;
+                app.adjType = "force-imp";
+                app.adjSource = app.forcingToImportant;
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
+            }
+        }
+
         if (app == mHeavyWeightProcess) {
             if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                 // We don't want to kill the current heavy-weight process.
@@ -21955,10 +22027,7 @@
                         + mConstants.SERVICE_USAGE_INTERACTION_TIME;
             }
         } else {
-            // If the app was being forced to the foreground, by say a Toast, then
-            // no need to treat it as an interaction
-            isInteraction = app.forcingToForeground == null
-                    && app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
+            isInteraction = app.curProcState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
             app.fgInteractionTime = 0;
         }
         if (isInteraction && (!app.reportedInteraction || (nowElapsed-app.interactionEventTime)
@@ -22059,7 +22128,14 @@
         return act;
     }
 
-    final boolean updateOomAdjLocked(ProcessRecord app) {
+    /**
+     * Update OomAdj for a specific process.
+     * @param app The process to update
+     * @param oomAdjAll If it's ok to call updateOomAdjLocked() for all running apps
+     *                  if necessary, or skip.
+     * @return whether updateOomAdjLocked(app) was successful.
+     */
+    final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
         final ActivityRecord TOP_ACT = resumedAppLocked();
         final ProcessRecord TOP_APP = TOP_ACT != null ? TOP_ACT.app : null;
         final boolean wasCached = app.cached;
@@ -22074,7 +22150,8 @@
                 ? app.curRawAdj : ProcessList.UNKNOWN_ADJ;
         boolean success = updateOomAdjLocked(app, cachedAdj, TOP_APP, false,
                 SystemClock.uptimeMillis());
-        if (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ) {
+        if (oomAdjAll
+                && (wasCached != app.cached || app.curRawAdj == ProcessList.UNKNOWN_ADJ)) {
             // Changed to/from cached state, so apps after it in the LRU
             // list may also be changed.
             updateOomAdjLocked();
@@ -22252,6 +22329,9 @@
                         if (uidRec.curProcState > app.curProcState) {
                             uidRec.curProcState = app.curProcState;
                         }
+                        if (app.foregroundServices) {
+                            uidRec.foregroundServices = true;
+                        }
                     }
                 }
 
@@ -22485,6 +22565,7 @@
                 } else {
                     if (uidRec.idle) {
                         uidChange = UidRecord.CHANGE_ACTIVE;
+                        EventLogTags.writeAmUidActive(uidRec.uid);
                         uidRec.idle = false;
                     }
                     uidRec.lastBackgroundTime = 0;
@@ -22493,6 +22574,9 @@
                 uidRec.setWhitelist = uidRec.curWhitelist;
                 enqueueUidChangeLocked(uidRec, -1, uidChange);
                 noteUidProcessState(uidRec.uid, uidRec.curProcState);
+                if (uidRec.foregroundServices) {
+                    mServices.foregroundServiceProcStateChangedLocked(uidRec);
+                }
             }
         }
         if (mLocalPowerManager != null) {
@@ -22560,6 +22644,7 @@
                         if (UserHandle.getAppId(uidRec.uid) == appId) {
                             if (userId == UserHandle.USER_ALL ||
                                     userId == UserHandle.getUserId(uidRec.uid)) {
+                                EventLogTags.writeAmUidIdle(uidRec.uid);
                                 uidRec.idle = true;
                                 Slog.w(TAG, "Idling uid " + UserHandle.formatUid(uidRec.uid)
                                         + " from package " + packageName + " user " + userId);
@@ -22594,6 +22679,7 @@
                 final long bgTime = uidRec.lastBackgroundTime;
                 if (bgTime > 0 && !uidRec.idle) {
                     if (bgTime <= maxBgTime) {
+                        EventLogTags.writeAmUidIdle(uidRec.uid);
                         uidRec.idle = true;
                         doStopUidLocked(uidRec.uid, uidRec);
                     } else {
@@ -23646,7 +23732,7 @@
                 }
                 pr.hasOverlayUi = hasOverlayUi;
                 //Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid);
-                updateOomAdjLocked(pr);
+                updateOomAdjLocked(pr, true);
             }
         }
 
@@ -23701,17 +23787,17 @@
 
         /**
          * Called after virtual display Id is updated by
-         * {@link com.android.server.vr.CompatibilityDisplay} with a specific
-         * {@param vrCompatibilityDisplayId}.
+         * {@link com.android.server.vr.Vr2dDisplay} with a specific
+         * {@param vrVr2dDisplayId}.
          */
         @Override
-        public void setVrCompatibilityDisplayId(int vrCompatibilityDisplayId) {
+        public void setVr2dDisplayId(int vr2dDisplayId) {
             if (DEBUG_STACK) {
-                Slog.d(TAG, "setVrCompatibilityDisplayId called for: " +
-                        vrCompatibilityDisplayId);
+                Slog.d(TAG, "setVr2dDisplayId called for: " +
+                        vr2dDisplayId);
             }
             synchronized (ActivityManagerService.this) {
-                mVrCompatibilityDisplayId = vrCompatibilityDisplayId;
+                mVr2dDisplayId = vr2dDisplayId;
             }
         }
     }
@@ -23775,11 +23861,8 @@
                 if (totalTime >= mWaitForNetworkTimeoutMs) {
                     Slog.wtf(TAG_NETWORK, "Total time waited for network rules to get updated: "
                             + totalTime + ". Uid: " + callingUid + " procStateSeq: "
-                            + procStateSeq);
-                } else if (DEBUG_NETWORK ||  totalTime >= mWaitForNetworkTimeoutMs / 2) {
-                    Slog.d(TAG_NETWORK, "Total time waited for network rules to get updated: "
-                            + totalTime + ". Uid: " + callingUid + " procStateSeq: "
-                            + procStateSeq);
+                            + procStateSeq + " UidRec: " + record
+                            + " validateUidRec: " + mValidateUids.get(callingUid));
                 }
             } catch (InterruptedException e) {
                 Thread.currentThread().interrupt();
@@ -23787,6 +23870,34 @@
         }
     }
 
+    public void waitForBroadcastIdle(PrintWriter pw) {
+        enforceCallingPermission(permission.DUMP, "waitForBroadcastIdle()");
+        while (true) {
+            boolean idle = true;
+            synchronized (this) {
+                for (BroadcastQueue queue : mBroadcastQueues) {
+                    if (!queue.isIdle()) {
+                        final String msg = "Waiting for queue " + queue + " to become idle...";
+                        pw.println(msg);
+                        pw.flush();
+                        Slog.v(TAG, msg);
+                        idle = false;
+                    }
+                }
+            }
+
+            if (idle) {
+                final String msg = "All broadcast queues are idle!";
+                pw.println(msg);
+                pw.flush();
+                Slog.v(TAG, msg);
+                return;
+            } else {
+                SystemClock.sleep(1000);
+            }
+        }
+    }
+
     /**
      * Return the user id of the last resumed activity.
      */
diff --git a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
index b6bfb00..dab122f 100644
--- a/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
+++ b/services/core/java/com/android/server/am/ActivityManagerShellCommand.java
@@ -251,6 +251,8 @@
                     return runUpdateApplicationInfo(pw);
                 case "no-home-screen":
                     return runNoHomeScreen(pw);
+                case "wait-for-broadcast-idle":
+                    return runWaitForBroadcastIdle(pw);
                 default:
                     return handleDefaultCommands(cmd);
             }
@@ -2419,6 +2421,11 @@
         return 0;
     }
 
+    int runWaitForBroadcastIdle(PrintWriter pw) throws RemoteException {
+        mInternal.waitForBroadcastIdle(pw);
+        return 0;
+    }
+
     private Resources getResources(PrintWriter pw) throws RemoteException {
         // system resources does not contain all the device configuration, construct it manually.
         Configuration config = mInterface.getConfiguration();
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index d4de521..bf7b663 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -10,6 +10,7 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.ActivityManagerInternal.APP_TRANSITION_TIMEOUT;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION;
+import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_BIND_APPLICATION_DELAY_MS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_CALLING_PACKAGE_NAME;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DELAY_MS;
 import static com.android.internal.logging.nano.MetricsProto.MetricsEvent.APP_TRANSITION_DEVICE_UPTIME_SECONDS;
@@ -78,7 +79,8 @@
         private int startResult;
         private boolean currentTransitionProcessRunning;
         private int windowsDrawnDelayMs;
-        private int startingWindowDelayMs;
+        private int startingWindowDelayMs = -1;
+        private int bindApplicationDelayMs = -1;
         private int reason = APP_TRANSITION_TIMEOUT;
         private boolean loggedWindowsDrawn;
         private boolean loggedStartingWindowDrawn;
@@ -296,6 +298,22 @@
         }
     }
 
+    /**
+     * Notifies the tracker that we called immediately before we call bindApplication on the client.
+     *
+     * @param app The client into which we'll call bindApplication.
+     */
+    void notifyBindApplication(ProcessRecord app) {
+        for (int i = mStackTransitionInfo.size() - 1; i >= 0; i--) {
+            final StackTransitionInfo info = mStackTransitionInfo.valueAt(i);
+
+            // App isn't attached to record yet, so match with info.
+            if (info.launchedActivity.appInfo == app.info) {
+                info.bindApplicationDelayMs = calculateCurrentDelay();
+            }
+        }
+    }
+
     private boolean allStacksWindowsDrawn() {
         for (int index = mStackTransitionInfo.size() - 1; index >= 0; index--) {
             if (!mStackTransitionInfo.valueAt(index).loggedWindowsDrawn) {
@@ -356,6 +374,10 @@
                 builder.addTaggedData(APP_TRANSITION_STARTING_WINDOW_DELAY_MS,
                         info.startingWindowDelayMs);
             }
+            if (info.bindApplicationDelayMs != -1) {
+                builder.addTaggedData(APP_TRANSITION_BIND_APPLICATION_DELAY_MS,
+                        info.bindApplicationDelayMs);
+            }
             builder.addTaggedData(APP_TRANSITION_WINDOWS_DRAWN_DELAY_MS, info.windowsDrawnDelayMs);
             mMetricsLogger.write(builder);
         }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 18c8b32..01fbdd4 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -40,6 +40,7 @@
 import static android.content.Intent.CATEGORY_HOME;
 import static android.content.Intent.CATEGORY_LAUNCHER;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_NO_HISTORY;
 import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_LAYOUT;
 import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
@@ -61,6 +62,7 @@
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.FLAG_NO_HISTORY;
 import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
 import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
 import static android.content.res.Configuration.EMPTY;
@@ -128,7 +130,6 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
-import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Debug;
@@ -248,6 +249,8 @@
     // Last configuration reported to the activity in the client process.
     private MergedConfiguration mLastReportedConfiguration;
     private int mLastReportedDisplayId;
+    private boolean mLastReportedMultiWindowMode;
+    private boolean mLastReportedPictureInPictureMode;
     CompatibilityInfo compat;// last used compatibility mode
     ActivityRecord resultTo; // who started this entry, so will get our reply
     final String resultWho; // additional identifier for use by resultTo.
@@ -288,10 +291,6 @@
     boolean frozenBeforeDestroy;// has been frozen but not yet destroyed.
     boolean immersive;      // immersive mode (don't interrupt if possible)
     boolean forceNewConfig; // force re-create with new config next time
-    private boolean mInMultiWindowMode; // whether or not this activity is currently in multi-window
-                                        // mode (default false)
-    private boolean mInPictureInPictureMode; // whether or not this activity is currently in
-                                             // picture-in-picture mode (default false)
     boolean supportsPictureInPictureWhilePausing;  // This flag is set by the system to indicate
         // that the activity can enter picture in picture while pausing (ie. only when another
         // task is brought to front or started)
@@ -534,6 +533,8 @@
         }
         if (info != null) {
             pw.println(prefix + "resizeMode=" + ActivityInfo.resizeModeToString(info.resizeMode));
+            pw.println(prefix + "mLastReportedMultiWindowMode=" + mLastReportedMultiWindowMode
+                    + " mLastReportedPictureInPictureMode=" + mLastReportedPictureInPictureMode);
             if (info.supportsPictureInPicture()) {
                 pw.println(prefix + "supportsPictureInPicture=" + info.supportsPictureInPicture());
                 pw.println(prefix + "supportsPictureInPictureWhilePausing: "
@@ -636,15 +637,15 @@
 
         // An activity is considered to be in multi-window mode if its task isn't fullscreen.
         final boolean inMultiWindowMode = !task.mFullscreen;
-        if (inMultiWindowMode != mInMultiWindowMode) {
-            mInMultiWindowMode = inMultiWindowMode;
+        if (inMultiWindowMode != mLastReportedMultiWindowMode) {
+            mLastReportedMultiWindowMode = inMultiWindowMode;
             scheduleMultiWindowModeChanged(getConfiguration());
         }
     }
 
     private void scheduleMultiWindowModeChanged(Configuration overrideConfig) {
         try {
-            app.thread.scheduleMultiWindowModeChanged(appToken, mInMultiWindowMode,
+            app.thread.scheduleMultiWindowModeChanged(appToken, mLastReportedMultiWindowMode,
                     overrideConfig);
         } catch (Exception e) {
             // If process died, I don't care.
@@ -658,11 +659,11 @@
 
         final boolean inPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID) &&
                 (targetStackBounds != null);
-        if (inPictureInPictureMode != mInPictureInPictureMode) {
+        if (inPictureInPictureMode != mLastReportedPictureInPictureMode) {
             // Picture-in-picture mode changes also trigger a multi-window mode change as well, so
             // update that here in order
-            mInPictureInPictureMode = inPictureInPictureMode;
-            mInMultiWindowMode = inPictureInPictureMode;
+            mLastReportedPictureInPictureMode = inPictureInPictureMode;
+            mLastReportedMultiWindowMode = inPictureInPictureMode;
             final Configuration newConfig = task.computeNewOverrideConfigurationForBounds(
                     targetStackBounds, null);
             schedulePictureInPictureModeChanged(newConfig);
@@ -672,7 +673,8 @@
 
     private void schedulePictureInPictureModeChanged(Configuration overrideConfig) {
         try {
-            app.thread.schedulePictureInPictureModeChanged(appToken, mInPictureInPictureMode,
+            app.thread.schedulePictureInPictureModeChanged(appToken,
+                    mLastReportedPictureInPictureMode,
                     overrideConfig);
         } catch (Exception e) {
             // If process died, no one cares.
@@ -939,6 +941,12 @@
 
         task.addActivityToTop(this);
 
+        // When an activity is started directly into a split-screen fullscreen stack, we need to
+        // update the initial multi-window modes so that the callbacks are scheduled correctly when
+        // the user leaves that mode.
+        mLastReportedMultiWindowMode = !task.mFullscreen;
+        mLastReportedPictureInPictureMode = (task.getStackId() == PINNED_STACK_ID);
+
         onOverrideConfigurationSent();
     }
 
@@ -1951,13 +1959,9 @@
             if (!nowVisible) {
                 nowVisible = true;
                 lastVisibleTime = SystemClock.uptimeMillis();
-                if (!idle) {
-                    // Instead of doing the full stop routine here, let's just hide any activities
-                    // we now can, and let them stop when the normal idle happens.
-                    mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
-                            false /* remove */, true /* processPausingActivities */);
-                } else {
-                    // If this activity was already idle, then we now need to make sure we perform
+                if (idle || mStackSupervisor.isStoppingNoHistoryActivity()) {
+                    // If this activity was already idle or there is an activity that must be
+                    // stopped immediately after visible, then we now need to make sure we perform
                     // the full stop of any activities that are waiting to do so. This is because
                     // we won't do that while they are still waiting for this one to become visible.
                     final int size = mStackSupervisor.mActivitiesWaitingForVisibleActivity.size();
@@ -1970,6 +1974,11 @@
                         mStackSupervisor.mActivitiesWaitingForVisibleActivity.clear();
                         mStackSupervisor.scheduleIdleLocked();
                     }
+                } else {
+                    // Instead of doing the full stop routine here, let's just hide any activities
+                    // we now can, and let them stop when the normal idle happens.
+                    mStackSupervisor.processStoppingActivitiesLocked(null /* idleActivity */,
+                            false /* remove */, true /* processPausingActivities */);
                 }
                 service.scheduleAppGcsLocked();
             }
@@ -2662,6 +2671,15 @@
         return true;
     }
 
+    /**
+     * Returns {@code true} if the associated activity has the no history flag set on it.
+     * {@code false} otherwise.
+     */
+    boolean isNoHistory() {
+        return (intent.getFlags() & FLAG_ACTIVITY_NO_HISTORY) != 0
+                || (info.flags & FLAG_NO_HISTORY) != 0;
+    }
+
     void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
         out.attribute(null, ATTR_ID, String.valueOf(createTime));
         out.attribute(null, ATTR_LAUNCHEDFROMUID, String.valueOf(launchedFromUid));
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d17309f..7aa363b 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -232,7 +232,7 @@
     static final int STACK_VISIBLE = 1;
     // Stack is considered visible, but only becuase it has activity that is visible behind other
     // activities and there is a specific combination of stacks.
-    private static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
+    static final int STACK_VISIBLE_ACTIVITY_BEHIND = 2;
 
     @VisibleForTesting
     /* The various modes for the method {@link #removeTask}. */
@@ -1652,28 +1652,20 @@
 
         if (StackId.isBackdropToTranslucentActivity(mStackId)
                 && hasVisibleBehindActivity() && StackId.isHomeOrRecentsStack(topStackId)
-                && !topStack.topActivity().fullscreen) {
+                && (topStack.topActivity() == null || !topStack.topActivity().fullscreen)) {
             // The fullscreen or assistant stack should be visible if it has a visible behind
             // activity behind the home or recents stack that is translucent.
             return STACK_VISIBLE_ACTIVITY_BEHIND;
         }
 
         if (mStackId == DOCKED_STACK_ID) {
-            final ActivityRecord r = topStack.topRunningActivityLocked();
-
             // If the assistant stack is focused and translucent, then the docked stack is always
             // visible
             if (topStack.isAssistantStack()) {
                 return (topStack.isStackTranslucent(starting, DOCKED_STACK_ID)) ? STACK_VISIBLE
                         : STACK_INVISIBLE;
             }
-
-            // Otherwise, the docked stack is always visible, except in the case where the top
-            // running activity task in the focus stack doesn't support any form of resizing but we
-            // show it for the home task even though it's not resizable.
-            final TaskRecord task = r != null ? r.getTask() : null;
-            return task == null || task.supportsSplitScreen() || task.isHomeTask() ? STACK_VISIBLE
-                    : STACK_INVISIBLE;
+            return STACK_VISIBLE;
         }
 
         // Set home stack to invisible when it is below but not immediately below the docked stack
@@ -1692,14 +1684,17 @@
                 mStacks.get(stackBehindTopIndex).topRunningActivityLocked() == null) {
             stackBehindTopIndex--;
         }
-        if ((topStackId == DOCKED_STACK_ID || topStackId == PINNED_STACK_ID)
-                && stackIndex == stackBehindTopIndex) {
-            // Stacks directly behind the docked or pinned stack are always visible.
-            return STACK_VISIBLE;
-        }
-
         final int stackBehindTopId = (stackBehindTopIndex >= 0)
                 ? mStacks.get(stackBehindTopIndex).mStackId : INVALID_STACK_ID;
+        if ((topStackId == DOCKED_STACK_ID || topStackId == PINNED_STACK_ID)
+                && (stackIndex == stackBehindTopIndex
+                || (stackBehindTopId == DOCKED_STACK_ID
+                && stackIndex == stackBehindTopIndex - 1))) {
+            // Stacks directly behind the docked or pinned stack are always visible.
+            // Also this stack is visible if behind docked stack and the docked stack is behind the
+            // top-most pinned stack
+            return STACK_VISIBLE;
+        }
 
         if (StackId.isBackdropToTranslucentActivity(topStackId)
                 && topStack.isStackTranslucent(starting, stackBehindTopId)) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 23b0607..f49d482 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3500,6 +3500,23 @@
         return mService.mUserController.isCurrentProfileLocked(userId);
     }
 
+    /**
+     * Returns whether a stopping activity is present that should be stopped after visible, rather
+     * than idle.
+     * @return {@code true} if such activity is present. {@code false} otherwise.
+     */
+    boolean isStoppingNoHistoryActivity() {
+        // Activities that are marked as nohistory should be stopped immediately after the resumed
+        // activity has become visible.
+        for (ActivityRecord record : mStoppingActivities) {
+            if (record.isNoHistory()) {
+                return true;
+            }
+        }
+
+        return false;
+    }
+
     final ArrayList<ActivityRecord> processStoppingActivitiesLocked(ActivityRecord idleActivity,
             boolean remove, boolean processPausingActivities) {
         ArrayList<ActivityRecord> stops = null;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 2273452..e33ae0d 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -186,7 +186,7 @@
     private IVoiceInteractionSession mVoiceSession;
     private IVoiceInteractor mVoiceInteractor;
 
-    private boolean mUsingVrCompatibilityDisplay;
+    private boolean mUsingVr2dDisplay;
 
     private void reset() {
         mStartActivity = null;
@@ -226,14 +226,14 @@
         mVoiceSession = null;
         mVoiceInteractor = null;
 
-        mUsingVrCompatibilityDisplay = false;
+        mUsingVr2dDisplay = false;
     }
 
     ActivityStarter(ActivityManagerService service, ActivityStackSupervisor supervisor) {
         mService = service;
         mSupervisor = supervisor;
         mInterceptor = new ActivityStartInterceptor(mService, mSupervisor);
-        mUsingVrCompatibilityDisplay = false;
+        mUsingVr2dDisplay = false;
     }
 
     final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,
@@ -534,7 +534,8 @@
                     verificationBundle, userId);
         }
         return InstantAppResolver.buildEphemeralInstallerIntent(originalIntent,
-            callingPackage, verificationBundle, resolvedType, userId, auxiliaryResponse.packageName,
+            auxiliaryResponse.failureIntent, callingPackage, verificationBundle,
+            resolvedType, userId, auxiliaryResponse.packageName,
             auxiliaryResponse.splitName, auxiliaryResponse.versionCode,
             auxiliaryResponse.token, auxiliaryResponse.needsPhaseTwo);
     }
@@ -575,12 +576,15 @@
             return;
         }
 
-        if (startedActivityStackId == PINNED_STACK_ID
-                && (result == START_TASK_TO_FRONT || result == START_DELIVERED_TO_TOP)) {
+        boolean clearedTask = (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+                == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK) && (mReuseTask != null);
+        if (startedActivityStackId == PINNED_STACK_ID && (result == START_TASK_TO_FRONT
+                || result == START_DELIVERED_TO_TOP || clearedTask)) {
             // The activity was already running in the pinned stack so it wasn't started, but either
             // brought to the front or the new intent was delivered to it since it was already in
             // front. Notify anyone interested in this piece of information.
-            mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt();
+            mService.mTaskChangeNotificationController.notifyPinnedActivityRestartAttempt(
+                    clearedTask);
             return;
         }
     }
@@ -1476,12 +1480,12 @@
         }
 
         // Get the virtual display id from ActivityManagerService.
-        int displayId = mService.mVrCompatibilityDisplayId;
+        int displayId = mService.mVr2dDisplayId;
         if (displayId != INVALID_DISPLAY) {
             if (DEBUG_STACK) {
                 Slog.d(TAG, "getSourceDisplayId :" + displayId);
             }
-            mUsingVrCompatibilityDisplay = true;
+            mUsingVr2dDisplay = true;
             return displayId;
         }
 
@@ -2105,8 +2109,8 @@
             return mSupervisor.getValidLaunchStackOnDisplay(launchDisplayId, r);
         }
 
-        // If we are using Vr compatibility display, find the virtual display stack.
-        if (mUsingVrCompatibilityDisplay) {
+        // If we are using Vr2d display, find the virtual display stack.
+        if (mUsingVr2dDisplay) {
             ActivityStack as = mSupervisor.getValidLaunchStackOnDisplay(mSourceDisplayId, r);
             if (DEBUG_STACK) {
                 Slog.v(TAG, "Launch stack for app: " + r.toString() +
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index d6bfb35..cfb5478 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -740,6 +740,8 @@
         }
         // If we've created a crash dialog, show it without the lock held
         if(data.proc.crashDialog != null) {
+            Slog.i(TAG, "Showing crash dialog for package " + data.proc.info.packageName
+                    + " u" + data.proc.userId);
             data.proc.crashDialog.show();
         }
     }
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 090234c..1705b58 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -51,7 +51,6 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.TimeUtils;
-import com.android.server.DeviceIdleController;
 
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 
@@ -204,6 +203,11 @@
         mDelayBehindServices = allowDelayBehindServices;
     }
 
+    @Override
+    public String toString() {
+        return mQueueName;
+    }
+
     public boolean isPendingBroadcastProcessLocked(int pid) {
         return mPendingBroadcast != null && mPendingBroadcast.curApp.pid == pid;
     }
@@ -682,7 +686,7 @@
                 // are already core system stuff so don't matter for this.
                 r.curApp = filter.receiverList.app;
                 filter.receiverList.app.curReceivers.add(r);
-                mService.updateOomAdjLocked(r.curApp);
+                mService.updateOomAdjLocked(r.curApp, true);
             }
         }
         try {
@@ -1572,6 +1576,11 @@
                 record.intent == null ? "" : record.intent.getAction());
     }
 
+    final boolean isIdle() {
+        return mParallelBroadcasts.isEmpty() && mOrderedBroadcasts.isEmpty()
+                && (mPendingBroadcast == null);
+    }
+
     final boolean dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args,
             int opti, boolean dumpAll, String dumpPackage, boolean needSep) {
         SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index f618fc7..372ab6b 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -114,3 +114,14 @@
 
 # UserState has changed
 30051 am_user_state_changed (id|1|5),(state|1|5)
+
+# Note when any processes of a uid have started running
+30052 am_uid_running (UID|1|5)
+# Note when all processes of a uid have stopped.
+30053 am_uid_stopped (UID|1|5)
+# Note when the state of a uid has become active.
+30054 am_uid_active (UID|1|5)
+# Note when the state of a uid has become idle (background check enforced).
+30055 am_uid_idle (UID|1|5)
+# Note when a service is being forcibly stopped because its app went idle.
+30056 am_stop_idle_service (UID|1|5),(Component Name|3)
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b025385..b222e3a 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -103,7 +103,6 @@
     int renderThreadTid;        // TID for RenderThread
     boolean serviceb;           // Process currently is on the service B list
     boolean serviceHighRam;     // We are forcing to service B list due to its RAM use
-    boolean setIsForeground;    // Running foreground UI when last set?
     boolean notCachedSinceIdle; // Has this process not been in a cached state since last idle?
     boolean hasClientActivities;  // Are there any client services with activities?
     boolean hasStartedServices; // Are there any started services running in this process?
@@ -136,7 +135,7 @@
     long interactionEventTime;  // The time we sent the last interaction event
     long fgInteractionTime;     // When we became foreground for interaction purposes
     String waitingToKill;       // Process is waiting to be killed when in the bg, and reason
-    IBinder forcingToForeground;// Token that is forcing this process to be foreground
+    Object forcingToImportant;  // Token that is forcing this process to be important
     int adjSeq;                 // Sequence id for identifying oom_adj assignment cycles
     int lruSeq;                 // Sequence id for identifying LRU update cycles
     CompatibilityInfo compat;   // last used compatibility mode
@@ -303,10 +302,9 @@
                     pw.print(" hasAboveClient="); pw.print(hasAboveClient);
                     pw.print(" treatLikeActivity="); pw.println(treatLikeActivity);
         }
-        if (setIsForeground || foregroundServices || forcingToForeground != null) {
-            pw.print(prefix); pw.print("setIsForeground="); pw.print(setIsForeground);
-                    pw.print(" foregroundServices="); pw.print(foregroundServices);
-                    pw.print(" forcingToForeground="); pw.println(forcingToForeground);
+        if (foregroundServices || forcingToImportant != null) {
+            pw.print(prefix); pw.print("foregroundServices="); pw.print(foregroundServices);
+                    pw.print(" forcingToImportant="); pw.println(forcingToImportant);
         }
         if (reportedInteraction || fgInteractionTime != 0) {
             pw.print(prefix); pw.print("reportedInteraction=");
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index 7d2bc5b..f5d7b68 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -104,7 +104,7 @@
     };
 
     private final TaskStackConsumer mNotifyPinnedActivityRestartAttempt = (l, m) -> {
-        l.onPinnedActivityRestartAttempt();
+        l.onPinnedActivityRestartAttempt(m.arg1 != 0);
     };
 
     private final TaskStackConsumer mNotifyPinnedStackAnimationStarted = (l, m) -> {
@@ -300,10 +300,11 @@
      * running in the pinned stack and the activity was not actually started, but the task is
      * either brought to the front or a new Intent is delivered to it.
      */
-    void notifyPinnedActivityRestartAttempt() {
+    void notifyPinnedActivityRestartAttempt(boolean clearedTask) {
         mHandler.removeMessages(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
         final Message msg =
-                mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG);
+                mHandler.obtainMessage(NOTIFY_PINNED_ACTIVITY_RESTART_ATTEMPT_LISTENERS_MSG,
+                        clearedTask ? 1 : 0, 0);
         forAllLocalListeners(mNotifyPinnedActivityRestartAttempt, msg);
         msg.sendToTarget();
     }
diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java
index c0fb77f..c411bce 100644
--- a/services/core/java/com/android/server/am/UidRecord.java
+++ b/services/core/java/com/android/server/am/UidRecord.java
@@ -35,6 +35,7 @@
     int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT;
     long lastBackgroundTime;
     boolean ephemeral;
+    boolean foregroundServices;
     boolean curWhitelist;
     boolean setWhitelist;
     boolean idle;
@@ -102,6 +103,7 @@
 
     public void reset() {
         curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
+        foregroundServices = false;
     }
 
     public void updateHasInternetPermission() {
@@ -131,6 +133,9 @@
         if (ephemeral) {
             sb.append(" ephemeral");
         }
+        if (foregroundServices) {
+            sb.append(" fgServices");
+        }
         if (curWhitelist) {
             sb.append(" whitelist");
         }
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 3b5e5bc..6a310f2 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -439,7 +439,7 @@
                 }
             }
 
-            Slog.d(TAG, "Sending BOOT_COMPLETE user #" + userId);
+            Slog.i(TAG, "Sending BOOT_COMPLETE user #" + userId);
             // Do not report secondary users, runtime restarts or first boot/upgrade
             if (userId == UserHandle.USER_SYSTEM
                     && !mInjector.isRuntimeRestarted() && !mInjector.isFirstBootOrUpgrade()) {
@@ -451,7 +451,14 @@
             bootIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
             bootIntent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT
                     | Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
-            mInjector.broadcastIntentLocked(bootIntent, null, null, 0, null, null,
+            mInjector.broadcastIntentLocked(bootIntent, null, new IIntentReceiver.Stub() {
+                @Override
+                public void performReceive(Intent intent, int resultCode, String data,
+                        Bundle extras, boolean ordered, boolean sticky, int sendingUser)
+                        throws RemoteException {
+                    Slog.i(UserController.TAG, "Finished processing BOOT_COMPLETED for u" + userId);
+                }
+            }, 0, null, null,
                     new String[] { android.Manifest.permission.RECEIVE_BOOT_COMPLETED },
                     AppOpsManager.OP_NONE, null, true, false, MY_PID, SYSTEM_UID, userId);
         }
diff --git a/services/core/java/com/android/server/audio/FocusRequester.java b/services/core/java/com/android/server/audio/FocusRequester.java
index 93a22494..125095c 100644
--- a/services/core/java/com/android/server/audio/FocusRequester.java
+++ b/services/core/java/com/android/server/audio/FocusRequester.java
@@ -310,7 +310,6 @@
      */
     void handleFocusGain(int focusGain) {
         try {
-            final int oldLoss = mFocusLossReceived;
             mFocusLossReceived = AudioManager.AUDIOFOCUS_NONE;
             mFocusController.notifyExtPolicyFocusGrant_syncAf(toAudioFocusInfo(),
                     AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
@@ -322,10 +321,9 @@
                 }
                 if (mFocusLossWasNotified) {
                     fd.dispatchAudioFocusChange(focusGain, mClientId);
-                } else if (oldLoss == AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK) {
-                    mFocusController.unduckPlayers(this);
                 }
             }
+            mFocusController.unduckPlayers(this);
             mFocusLossWasNotified = false;
         } catch (android.os.RemoteException e) {
             Log.e(TAG, "Failure to signal gain of audio focus due to: ", e);
@@ -335,6 +333,15 @@
     /**
      * Called synchronized on MediaFocusControl.mAudioFocusLock
      */
+    void handleFocusGainFromRequest(int focusRequestResult) {
+        if (focusRequestResult == AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
+            mFocusController.unduckPlayers(this);
+        }
+    }
+
+    /**
+     * Called synchronized on MediaFocusControl.mAudioFocusLock
+     */
     void handleFocusLoss(int focusLoss, @Nullable final FocusRequester fr) {
         try {
             if (focusLoss != mFocusLossReceived) {
@@ -383,6 +390,8 @@
                         Log.v(TAG, "NOT dispatching " + focusChangeToString(mFocusLossReceived)
                             + " to " + mClientId + ", ducking implemented by framework");
                     }
+                    mFocusController.notifyExtPolicyFocusLoss_syncAf(
+                            toAudioFocusInfo(), false /* wasDispatched */);
                     return; // with mFocusLossWasNotified = false
                 }
 
diff --git a/services/core/java/com/android/server/audio/MediaFocusControl.java b/services/core/java/com/android/server/audio/MediaFocusControl.java
index f5c13c1..7d742ff 100644
--- a/services/core/java/com/android/server/audio/MediaFocusControl.java
+++ b/services/core/java/com/android/server/audio/MediaFocusControl.java
@@ -752,6 +752,7 @@
 
                 // push focus requester at the top of the audio focus stack
                 mFocusStack.push(nfr);
+                nfr.handleFocusGainFromRequest(AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
             }
             notifyExtPolicyFocusGrant_syncAf(nfr.toAudioFocusInfo(),
                     AudioManager.AUDIOFOCUS_REQUEST_GRANTED);
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index d35104f..3053879 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -18,12 +18,10 @@
 
 import android.annotation.NonNull;
 import android.media.AudioAttributes;
-import android.media.AudioFormat;
 import android.media.AudioManager;
 import android.media.AudioPlaybackConfiguration;
 import android.media.AudioSystem;
 import android.media.IPlaybackConfigDispatcher;
-import android.media.MediaRecorder;
 import android.media.PlayerBase;
 import android.media.VolumeShaper;
 import android.os.Binder;
@@ -99,13 +97,6 @@
         apc.init();
         synchronized(mPlayerLock) {
             mPlayers.put(newPiid, apc);
-            if (mDuckedUids.contains(new Integer(apc.getClientUid()))) {
-                if (DEBUG) { Log.v(TAG, "  > trackPlayer() piid=" + newPiid + " must be ducked"); }
-                mDuckedPlayers.add(new Integer(newPiid));
-                // FIXME here the player needs to be put in a state that is the same as if it
-                //   had been ducked as it starts. At the moment, this works already for linked
-                //   players, as is the case in gapless playback.
-            }
         }
         return newPiid;
     }
@@ -131,10 +122,11 @@
         final boolean change;
         synchronized(mPlayerLock) {
             final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
-            // FIXME SoundPool not ready for state reporting
-            if (apc != null
-                    && apc.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL)
-            {
+            if (apc == null) {
+                return;
+            }
+            if (apc.getPlayerType() == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
+                // FIXME SoundPool not ready for state reporting
                 return;
             }
             if (checkConfigurationCaller(piid, apc, binderUid)) {
@@ -144,12 +136,8 @@
                 Log.e(TAG, "Error handling event " + event);
                 change = false;
             }
-            if (change && event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
-                    && mDuckedUids.contains(new Integer(apc.getClientUid()))) {
-                if (DEBUG) { Log.v(TAG, "  > playerEvent() piid=" + piid + " must be ducked"); }
-                if (!mDuckedPlayers.contains(new Integer(piid))) {
-                    mDuckedPlayers.add(new Integer(piid));
-                }
+            if (change && event == AudioPlaybackConfiguration.PLAYER_STATE_STARTED) {
+                mDuckingManager.checkDuck(apc);
             }
         }
         if (change) {
@@ -163,6 +151,7 @@
             final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
             if (checkConfigurationCaller(piid, apc, binderUid)) {
                 mPlayers.remove(new Integer(piid));
+                mDuckingManager.removeReleased(apc);
             }
         }
     }
@@ -182,10 +171,8 @@
                 conf.dump(pw);
             }
             // ducked players
-            pw.println("\n  ducked player piids:");
-            for (int piid : mDuckedPlayers) {
-                pw.println(" " + piid);
-            }
+            pw.println("\n  ducked players:");
+            mDuckingManager.dump(pw);
             // players muted due to the device ringing or being in a call
             pw.println("\n  muted player piids:");
             for (int piid : mMutedPlayers) {
@@ -274,10 +261,9 @@
 
     //=================================================================
     // PlayerFocusEnforcer implementation
-    private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
     private final ArrayList<Integer> mMutedPlayers = new ArrayList<Integer>();
-    // size of 2 for typical cases of double-ducking, not expected to grow beyond that, but can
-    private final ArrayList<Integer> mDuckedUids = new ArrayList<Integer>(2);
+
+    private final DuckingManager mDuckingManager = new DuckingManager();
 
     @Override
     public boolean duckPlayers(FocusRequester winner, FocusRequester loser) {
@@ -286,60 +272,46 @@
                     winner.getClientUid(), loser.getClientUid()));
         }
         synchronized (mPlayerLock) {
-            final Integer loserUid = new Integer(loser.getClientUid());
-            if (!mDuckedUids.contains(loserUid)) {
-                mDuckedUids.add(loserUid);
-            }
             if (mPlayers.isEmpty()) {
                 return true;
             }
-            final Set<Integer> piidSet = mPlayers.keySet();
-            final Iterator<Integer> piidIterator = piidSet.iterator();
-            // find which players to duck
-            while (piidIterator.hasNext()) {
-                final Integer piid = piidIterator.next();
-                final AudioPlaybackConfiguration apc = mPlayers.get(piid);
-                if (apc == null) {
-                    continue;
-                }
+            // check if this UID needs to be ducked (return false if not), and gather list of
+            // eligible players to duck
+            final Iterator<AudioPlaybackConfiguration> apcIterator = mPlayers.values().iterator();
+            final ArrayList<AudioPlaybackConfiguration> apcsToDuck =
+                    new ArrayList<AudioPlaybackConfiguration>();
+            while (apcIterator.hasNext()) {
+                final AudioPlaybackConfiguration apc = apcIterator.next();
                 if (!winner.hasSameUid(apc.getClientUid())
                         && loser.hasSameUid(apc.getClientUid())
                         && apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED)
                 {
-                    if (mDuckedPlayers.contains(new Integer(piid))) {
-                        if (DEBUG) { Log.v(TAG, "player " + piid + " already ducked"); }
-                    } else if (MediaFocusControl.ENFORCE_DUCKING
+                    if (MediaFocusControl.ENFORCE_DUCKING
                             && MediaFocusControl.ENFORCE_DUCKING_FOR_NEW
                             && loser.getSdkTarget() <= MediaFocusControl.DUCKING_IN_APP_SDK_LEVEL) {
                         // legacy behavior, apps used to be notified when they should be ducking
-                        if (DEBUG) { Log.v(TAG, "not ducking player " + piid + ": old SDK"); }
+                        if (DEBUG) {Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
+                                + ": old SDK"); }
                         return false;
                     } else if (apc.getAudioAttributes().getContentType() ==
                             AudioAttributes.CONTENT_TYPE_SPEECH) {
                         // the player is speaking, ducking will make the speech unintelligible
                         // so let the app handle it instead
-                        if (DEBUG) { Log.v(TAG, "not ducking player " + piid + ": SPEECH"); }
+                        if (DEBUG) { Log.v(TAG, "not ducking player " + apc.getPlayerInterfaceId()
+                                + ": SPEECH"); }
                         return false;
                     } else if (apc.getPlayerType()
                             == AudioPlaybackConfiguration.PLAYER_TYPE_JAM_SOUNDPOOL) {
                         // TODO support ducking of SoundPool players
                         return false;
-                    } else {
-                        try {
-                            Log.v(TAG, "ducking player " + piid);
-                            apc.getPlayerProxy().applyVolumeShaper(
-                                    DUCK_VSHAPE,
-                                    PLAY_CREATE_IF_NEEDED);
-                            mDuckedPlayers.add(new Integer(piid));
-                        } catch (Exception e) {
-                            Log.e(TAG, "Error ducking player " + piid, e);
-                            // something went wrong trying to duck, so let the app handle it
-                            // instead, it may know things we don't
-                            return false;
-                        }
                     }
+                    apcsToDuck.add(apc);
                 }
             }
+            // add the players eligible for ducking to the list, and duck them
+            // (if apcsToDuck is empty, this will at least mark this uid as ducked, so when
+            //  players of the same uid start, they will be ducked by DuckingManager.checkDuck())
+            mDuckingManager.duckUid(loser.getClientUid(), apcsToDuck);
         }
         return true;
     }
@@ -348,37 +320,7 @@
     public void unduckPlayers(FocusRequester winner) {
         if (DEBUG) { Log.v(TAG, "unduckPlayers: uids winner=" + winner.getClientUid()); }
         synchronized (mPlayerLock) {
-            if (mDuckedPlayers.isEmpty()) {
-                mDuckedUids.remove(new Integer(winner.getClientUid()));
-                return;
-            }
-            final ArrayList<Integer> playersToRemove =
-                    new ArrayList<Integer>(mDuckedPlayers.size());
-            for (int piid : mDuckedPlayers) {
-                final AudioPlaybackConfiguration apc = mPlayers.get(piid);
-                if (apc != null) {
-                    if (winner.hasSameUid(apc.getClientUid())) {
-                        try {
-                            Log.v(TAG, "unducking player " + piid);
-                            apc.getPlayerProxy().applyVolumeShaper(
-                                    DUCK_ID,
-                                    VolumeShaper.Operation.REVERSE);
-                        } catch (Exception e) {
-                            Log.e(TAG, "Error unducking player " + piid, e);
-                        } finally {
-                            playersToRemove.add(piid);
-                        }
-                    }
-                } else {
-                    // this piid was in the list of ducked players, but wasn't found, discard it
-                    Log.v(TAG, "Error unducking player " + piid + ", player not found");
-                    playersToRemove.add(piid);
-                }
-            }
-            for (int piid : playersToRemove) {
-                mDuckedPlayers.remove(new Integer(piid));
-            }
-            mDuckedUids.remove(new Integer(winner.getClientUid()));
+            mDuckingManager.unduckUid(winner.getClientUid(), mPlayers);
         }
     }
 
@@ -541,4 +483,118 @@
             mDispatcherCb.asBinder().unlinkToDeath(this, 0);
         }
     }
+
+    //=================================================================
+    // Class to handle ducking related operations for a given UID
+    private static final class DuckingManager {
+        private final HashMap<Integer, DuckedApp> mDuckers = new HashMap<Integer, DuckedApp>();
+
+        void duckUid(int uid, ArrayList<AudioPlaybackConfiguration> apcsToDuck) {
+            if (!mDuckers.containsKey(uid)) {
+                mDuckers.put(uid, new DuckedApp(uid));
+            }
+            final DuckedApp da = mDuckers.get(uid);
+            for (AudioPlaybackConfiguration apc : apcsToDuck) {
+                da.addDuck(apc);
+            }
+        }
+
+        void unduckUid(int uid, HashMap<Integer, AudioPlaybackConfiguration> players) {
+            final DuckedApp da = mDuckers.remove(uid);
+            if (da == null) {
+                return;
+            }
+            da.removeUnduckAll(players);
+        }
+
+        // pre-condition: apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
+        void checkDuck(@NonNull AudioPlaybackConfiguration apc) {
+            final DuckedApp da = mDuckers.get(apc.getClientUid());
+            if (da == null) {
+                return;
+            }
+            // FIXME here the player needs to be put in a state that is the same as if it
+            //   had been ducked as it starts. At the moment, this works already for linked
+            //   players, as is the case in gapless playback.
+            da.addDuck(apc);
+        }
+
+        void dump(PrintWriter pw) {
+            for (DuckedApp da : mDuckers.values()) {
+                da.dump(pw);
+            }
+        }
+
+        void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
+            final DuckedApp da = mDuckers.get(apc.getClientUid());
+            if (da == null) {
+                return;
+            }
+            da.removeReleased(apc);
+        }
+
+        private static final class DuckedApp {
+            private final int mUid;
+            private final ArrayList<Integer> mDuckedPlayers = new ArrayList<Integer>();
+
+            DuckedApp(int uid) {
+                mUid = uid;
+            }
+
+            void dump(PrintWriter pw) {
+                pw.print("\t uid:" + mUid + " piids:");
+                for (int piid : mDuckedPlayers) {
+                    pw.print(" " + piid);
+                }
+                pw.println("");
+            }
+
+            // pre-conditions:
+            //  * apc != null
+            //  * apc.getPlayerState() == AudioPlaybackConfiguration.PLAYER_STATE_STARTED
+            void addDuck(@NonNull AudioPlaybackConfiguration apc) {
+                final int piid = new Integer(apc.getPlayerInterfaceId());
+                if (mDuckedPlayers.contains(piid)) {
+                    if (DEBUG) { Log.v(TAG, "player " + piid + " already ducked"); }
+                    return;
+                }
+                try {
+                    Log.v(TAG, "ducking player " + apc.getPlayerInterfaceId());
+                    apc.getPlayerProxy().applyVolumeShaper(
+                            DUCK_VSHAPE,
+                            PLAY_CREATE_IF_NEEDED);
+                    mDuckedPlayers.add(piid);
+                } catch (Exception e) {
+                    Log.e(TAG, "Error ducking player " + piid, e);
+                }
+            }
+
+            void removeUnduckAll(HashMap<Integer, AudioPlaybackConfiguration> players) {
+                for (int piid : mDuckedPlayers) {
+                    final AudioPlaybackConfiguration apc = players.get(piid);
+                    if (apc != null) {
+                        try {
+                            Log.v(TAG, "unducking player " + piid);
+                            apc.getPlayerProxy().applyVolumeShaper(
+                                    DUCK_ID,
+                                    VolumeShaper.Operation.REVERSE);
+                        } catch (Exception e) {
+                            Log.e(TAG, "Error unducking player " + piid, e);
+                        }
+                    } else {
+                        // this piid was in the list of ducked players, but wasn't found
+                        if (DEBUG) {
+                            Log.v(TAG, "Error unducking player " + piid + ", player not found for"
+                                    + " uid " + mUid);
+                        }
+                    }
+                }
+                mDuckedPlayers.clear();
+            }
+
+            void removeReleased(@NonNull AudioPlaybackConfiguration apc) {
+                mDuckedPlayers.remove(new Integer(apc.getPlayerInterfaceId()));
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/display/NightDisplayService.java b/services/core/java/com/android/server/display/NightDisplayService.java
index 7849896..d574265 100644
--- a/services/core/java/com/android/server/display/NightDisplayService.java
+++ b/services/core/java/com/android/server/display/NightDisplayService.java
@@ -567,22 +567,27 @@
 
         private final TwilightManager mTwilightManager;
 
-        private Calendar mLastActivatedTime;
-
         TwilightAutoMode() {
             mTwilightManager = getLocalService(TwilightManager.class);
         }
 
         private void updateActivated(TwilightState state) {
-            boolean activate = state != null && state.isNight();
-            if (state != null && mLastActivatedTime != null) {
+            if (state == null) {
+                // If there isn't a valid TwilightState then just keep the current activated
+                // state.
+                return;
+            }
+
+            boolean activate = state.isNight();
+            final Calendar lastActivatedTime = getLastActivatedTime();
+            if (lastActivatedTime != null) {
                 final Calendar now = Calendar.getInstance();
                 final Calendar sunrise = state.sunrise();
                 final Calendar sunset = state.sunset();
 
                 // Maintain the existing activated state if within the current period.
-                if (mLastActivatedTime.before(now)
-                        && (mLastActivatedTime.after(sunrise) ^ mLastActivatedTime.after(sunset))) {
+                if (lastActivatedTime.before(now)
+                        && (lastActivatedTime.after(sunrise) ^ lastActivatedTime.after(sunset))) {
                     activate = mController.isActivated();
                 }
             }
@@ -595,7 +600,6 @@
         @Override
         public void onStart() {
             mTwilightManager.registerListener(this, mHandler);
-            mLastActivatedTime = getLastActivatedTime();
 
             // Force an update to initialize state.
             updateActivated(mTwilightManager.getLastTwilightState());
@@ -604,14 +608,10 @@
         @Override
         public void onStop() {
             mTwilightManager.unregisterListener(this);
-            mLastActivatedTime = null;
         }
 
         @Override
         public void onActivated(boolean activated) {
-            if (mIsActivated != null) {
-                mLastActivatedTime = getLastActivatedTime();
-            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
index 6610634..88a6bdd 100644
--- a/services/core/java/com/android/server/fingerprint/RemovalClient.java
+++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java
@@ -91,7 +91,7 @@
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to notify Removed:", e);
         }
-        return fingerId == 0;
+        return remaining == 0;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index aafc9a8..0e52871 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -230,6 +230,9 @@
     private static native void nativeReloadDeviceAliases(long ptr);
     private static native String nativeDump(long ptr);
     private static native void nativeMonitor(long ptr);
+    private static native boolean nativeIsInputDeviceEnabled(long ptr, int deviceId);
+    private static native void nativeEnableInputDevice(long ptr, int deviceId);
+    private static native void nativeDisableInputDevice(long ptr, int deviceId);
     private static native void nativeSetPointerIconType(long ptr, int iconId);
     private static native void nativeReloadPointerIcons(long ptr);
     private static native void nativeSetCustomPointerIcon(long ptr, PointerIcon icon);
@@ -639,6 +642,32 @@
         return null;
     }
 
+    // Binder call
+    @Override
+    public boolean isInputDeviceEnabled(int deviceId) {
+        return nativeIsInputDeviceEnabled(mPtr, deviceId);
+    }
+
+    // Binder call
+    @Override
+    public void enableInputDevice(int deviceId) {
+        if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
+                "enableInputDevice()")) {
+            throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
+        }
+        nativeEnableInputDevice(mPtr, deviceId);
+    }
+
+    // Binder call
+    @Override
+    public void disableInputDevice(int deviceId) {
+        if (!checkCallingPermission(android.Manifest.permission.DISABLE_INPUT_DEVICE,
+                "disableInputDevice()")) {
+            throw new SecurityException("Requires DISABLE_INPUT_DEVICE permission");
+        }
+        nativeDisableInputDevice(mPtr, deviceId);
+    }
+
     /**
      * Gets the ids of all input devices in the system.
      * @return The input device ids.
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index 4b632fe..45971f5 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1184,21 +1184,29 @@
 
     @Override
     public int getStatus(Bundle extras) {
-        if (extras != null) {
-            extras.putInt("satellites", mSvCount);
-        }
+        setLocationExtras(extras);
         return mStatus;
     }
 
-    private void updateStatus(int status, int svCount) {
-        if (status != mStatus || svCount != mSvCount) {
+    private void updateStatus(int status, int svCount, int meanCn0, int maxCn0) {
+        if (status != mStatus || svCount != mSvCount || meanCn0 != mMeanCn0 || maxCn0 != mMaxCn0 ) {
             mStatus = status;
             mSvCount = svCount;
-            mLocationExtras.putInt("satellites", svCount);
+            mMeanCn0 = meanCn0;
+            mMaxCn0 = maxCn0;
+            setLocationExtras(mLocationExtras);
             mStatusUpdateTime = SystemClock.elapsedRealtime();
         }
     }
 
+    private void setLocationExtras(Bundle extras) {
+        if (extras != null) {
+            extras.putInt("satellites", mSvCount);
+            extras.putInt("meanCn0", mMeanCn0);
+            extras.putInt("maxCn0", mMaxCn0);
+        }
+    }
+
     @Override
     public long getStatusUpdateTime() {
         return mStatusUpdateTime;
@@ -1449,7 +1457,7 @@
             }
 
             // reset SV count to zero
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
             mFixRequestTime = System.currentTimeMillis();
             if (!hasCapability(GPS_CAPABILITY_SCHEDULING)) {
                 // set timer to give up if we do not receive a fix within NO_FIX_TIMEOUT
@@ -1472,7 +1480,7 @@
             mLastFixTime = 0;
 
             // reset SV count to zero
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0);
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, 0, 0, 0);
         }
     }
 
@@ -1558,7 +1566,7 @@
             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, true);
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            updateStatus(LocationProvider.AVAILABLE, mSvCount);
+            updateStatus(LocationProvider.AVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
         }
 
        if (!hasCapability(GPS_CAPABILITY_SCHEDULING) && mStarted &&
@@ -1622,15 +1630,21 @@
         if (VERBOSE) {
             Log.v(TAG, "SV count: " + svCount);
         }
-        // Calculate number of sets used in fix.
+        // Calculate number of satellites used in fix.
         int usedInFixCount = 0;
+        int maxCn0 = 0;
+        int meanCn0 = 0;
         for (int i = 0; i < svCount; i++) {
             if ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_USED_IN_FIX) != 0) {
                 ++usedInFixCount;
+                if (mCn0s[i] > maxCn0) {
+                    maxCn0 = (int)mCn0s[i];
+                }
+                meanCn0 += mCn0s[i];
             }
             if (VERBOSE) {
                 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
-                        " cn0: " + mCn0s[i]/10 +
+                        " cn0: " + mCn0s[i] +
                         " elev: " + mSvElevations[i] +
                         " azimuth: " + mSvAzimuths[i] +
                         " carrier frequency: " + mSvCarrierFreqs[i] +
@@ -1644,8 +1658,11 @@
                         ? "" : "F"));
             }
         }
-        // return number of sets used in fix instead of total
-        updateStatus(mStatus, usedInFixCount);
+        if (usedInFixCount > 0) {
+            meanCn0 /= usedInFixCount;
+        }
+        // return number of sats used in fix instead of total reported
+        updateStatus(mStatus, usedInFixCount, meanCn0, maxCn0);
 
         if (mNavigating && mStatus == LocationProvider.AVAILABLE && mLastFixTime > 0 &&
             System.currentTimeMillis() - mLastFixTime > RECENT_FIX_TIMEOUT) {
@@ -1653,7 +1670,7 @@
             Intent intent = new Intent(LocationManager.GPS_FIX_CHANGE_ACTION);
             intent.putExtra(LocationManager.EXTRA_GPS_ENABLED, false);
             mContext.sendBroadcastAsUser(intent, UserHandle.ALL);
-            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount);
+            updateStatus(LocationProvider.TEMPORARILY_UNAVAILABLE, mSvCount, mMeanCn0, mMaxCn0);
         }
     }
 
@@ -2531,6 +2548,8 @@
     private float mSvAzimuths[] = new float[MAX_SVS];
     private float mSvCarrierFreqs[] = new float[MAX_SVS];
     private int mSvCount;
+    private int mMeanCn0;
+    private int mMaxCn0;
     // preallocated to avoid memory allocation in reportNmea()
     private byte[] mNmeaBuffer = new byte[120];
 
diff --git a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
index f92bf3d..4981d5c 100644
--- a/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
+++ b/services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
@@ -66,7 +66,11 @@
 
             @Override
             public void applyChangesLocked(NotificationRecord record) {
-                record.setRecentlyIntrusive(false);
+                // there will be another reconsideration in the message queue HANG_TIME_MS
+                // from each time this record alerts, which can finally clear this flag.
+                if ((System.currentTimeMillis() - record.getLastIntrusive()) >= HANG_TIME_MS) {
+                    record.setRecentlyIntrusive(false);
+                }
             }
         };
     }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 48d11c3..70766f9 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -884,6 +884,8 @@
             } else if (action.equals(Intent.ACTION_USER_REMOVED)) {
                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                 mZenModeHelper.onUserRemoved(user);
+                mRankingHelper.onUserRemoved(user);
+                savePolicyFile();
             } else if (action.equals(Intent.ACTION_USER_UNLOCKED)) {
                 final int user = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                 mConditionProviders.onUserUnlocked(user);
@@ -2869,8 +2871,7 @@
                                 adjustedSbn.getUser(), GroupHelper.AUTOGROUP_KEY,
                                 System.currentTimeMillis());
                 summaryRecord = new NotificationRecord(getContext(), summarySbn,
-                        notificationRecord.getChannel(), mRankingHelper.supportsChannels(
-                                summarySbn.getPackageName(), summarySbn.getUid()));
+                        notificationRecord.getChannel());
                 summaries.put(pkg, summarySbn.getKey());
             }
         }
@@ -3199,10 +3200,8 @@
                     + ", incomingUserId=" + incomingUserId
                     + ", notificationUid=" + notificationUid
                     + ", notification=" + notification;
-            // STOPSHIP TODO: should throw instead of logging or toasting.
-            // throw new IllegalArgumentException(noChannelStr);
             Log.e(TAG, noChannelStr);
-            doDebugOnlyToast("Developer warning for package \"" + pkg + "\"\n" +
+            doChannelWarningToast("Developer warning for package \"" + pkg + "\"\n" +
                     "Failed to post notification on channel \"" + channelId + "\"\n" +
                     "See log for more details");
             return;
@@ -3211,8 +3210,7 @@
         final StatusBarNotification n = new StatusBarNotification(
                 pkg, opPkg, id, tag, notificationUid, callingPid, notification,
                 user, null, System.currentTimeMillis());
-        final NotificationRecord r = new NotificationRecord(getContext(), n, channel,
-                mRankingHelper.supportsChannels(pkg, notificationUid));
+        final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
 
         if (!checkDisqualifyingFeatures(userId, notificationUid, id,tag, r)) {
             return;
@@ -3238,8 +3236,10 @@
         mHandler.post(new EnqueueNotificationRunnable(userId, r));
     }
 
-    private void doDebugOnlyToast(CharSequence toastText) {
-        if (Build.IS_DEBUGGABLE) {
+    private void doChannelWarningToast(CharSequence toastText) {
+        final boolean warningEnabled = Settings.System.getInt(getContext().getContentResolver(),
+                Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS, 0) != 0;
+        if (warningEnabled || Build.IS_DEBUGGABLE) {
             try {
                 Toast toast = Toast.makeText(getContext(), toastText, Toast.LENGTH_LONG);
                 toast.show();
@@ -3935,7 +3935,7 @@
             }
         }
         try {
-            mAm.setProcessForeground(mForegroundToken, pid, toastCount > 0);
+            mAm.setProcessImportant(mForegroundToken, pid, toastCount > 0, "toast");
         } catch (RemoteException e) {
             // Shouldn't happen.
         }
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 90257da..5a5e658 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -85,6 +85,7 @@
     // to communicate with the ranking module.
     private float mContactAffinity;
     private boolean mRecentlyIntrusive;
+    private long mLastIntrusive;
 
     // is this notification currently being intercepted by Zen Mode?
     private boolean mIntercept;
@@ -115,7 +116,7 @@
     private int mSuppressedVisualEffects = 0;
     private String mUserExplanation;
     private String mPeopleExplanation;
-    private boolean mSupportsChannels = false;
+    private boolean mPreChannelsNotification = true;
     private Uri mSound;
     private long[] mVibration;
     private AudioAttributes mAttributes;
@@ -128,7 +129,7 @@
 
     @VisibleForTesting
     public NotificationRecord(Context context, StatusBarNotification sbn,
-            NotificationChannel channel, boolean supportsChannels)
+            NotificationChannel channel)
     {
         this.sbn = sbn;
         mOriginalFlags = sbn.getNotification().flags;
@@ -138,7 +139,7 @@
         mContext = context;
         stats = new NotificationUsageStats.SingleNotificationStats();
         mChannel = channel;
-        mSupportsChannels = supportsChannels;
+        mPreChannelsNotification = isPreChannelsNotification();
         mSound = calculateSound();
         mVibration = calculateVibration();
         mAttributes = calculateAttributes();
@@ -146,11 +147,27 @@
         mLight = calculateLights();
     }
 
+    private boolean isPreChannelsNotification() {
+        try {
+            if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(getChannel().getId())) {
+                  final ApplicationInfo applicationInfo =
+                        mContext.getPackageManager().getApplicationInfoAsUser(sbn.getPackageName(),
+                                0, UserHandle.getUserId(sbn.getUid()));
+                if (applicationInfo.targetSdkVersion <= Build.VERSION_CODES.N_MR1) {
+                    return true;
+                }
+            }
+        } catch (NameNotFoundException e) {
+            Slog.e(TAG, "Can't find package", e);
+        }
+        return false;
+    }
+
     private Uri calculateSound() {
         final Notification n = sbn.getNotification();
 
         Uri sound = mChannel.getSound();
-        if (!mSupportsChannels && (getChannel().getUserLockedFields()
+        if (mPreChannelsNotification && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
 
             final boolean useDefaultSound = (n.defaults & Notification.DEFAULT_SOUND) != 0;
@@ -175,7 +192,7 @@
                 : defaultLightColor;
         Light light = getChannel().shouldShowLights() ? new Light(channelLightColor,
                 defaultLightOn, defaultLightOff) : null;
-        if (!mSupportsChannels
+        if (mPreChannelsNotification
                 && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_LIGHTS) == 0) {
             final Notification notification = sbn.getNotification();
@@ -206,7 +223,7 @@
         } else {
             vibration = null;
         }
-        if (!mSupportsChannels
+        if (mPreChannelsNotification
                 && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_VIBRATION) == 0) {
             final Notification notification = sbn.getNotification();
@@ -228,7 +245,7 @@
             attributes = Notification.AUDIO_ATTRIBUTES_DEFAULT;
         }
 
-        if (!mSupportsChannels
+        if (mPreChannelsNotification
                 && (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_SOUND) == 0) {
             if (n.audioAttributes != null) {
@@ -277,7 +294,7 @@
         stats.requestedImportance = requestedImportance;
         stats.isNoisy = mSound != null || mVibration != null;
 
-        if (!mSupportsChannels
+        if (mPreChannelsNotification
                 && (importance == IMPORTANCE_UNSPECIFIED
                 || (getChannel().getUserLockedFields()
                 & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0)) {
@@ -444,7 +461,7 @@
         pw.println(prefix + "mVisibleSinceMs=" + mVisibleSinceMs);
         pw.println(prefix + "mUpdateTimeMs=" + mUpdateTimeMs);
         pw.println(prefix + "mSuppressedVisualEffects= " + mSuppressedVisualEffects);
-        if (!mSupportsChannels) {
+        if (mPreChannelsNotification) {
             pw.println(prefix + String.format("defaults=0x%08x flags=0x%08x",
                     notification.defaults, notification.flags));
             pw.println(prefix + "n.sound=" + notification.sound);
@@ -515,12 +532,19 @@
 
     public void setRecentlyIntrusive(boolean recentlyIntrusive) {
         mRecentlyIntrusive = recentlyIntrusive;
+        if (recentlyIntrusive) {
+            mLastIntrusive = System.currentTimeMillis();
+        }
     }
 
     public boolean isRecentlyIntrusive() {
         return mRecentlyIntrusive;
     }
 
+    public long getLastIntrusive() {
+        return mLastIntrusive;
+    }
+
     public void setPackagePriority(int packagePriority) {
         mPackagePriority = packagePriority;
     }
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 14d796f..4d19b52 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -42,6 +42,4 @@
     void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
     void permanentlyDeleteNotificationChannels(String pkg, int uid);
     ParceledListSlice<NotificationChannel> getNotificationChannels(String pkg, int uid, boolean includeDeleted);
-
-    boolean supportsChannels(String pkg, int uid);
 }
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 3481556..7758516 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -273,14 +273,8 @@
     }
 
     private boolean shouldHaveDefaultChannel(Record r) throws NameNotFoundException {
-        if (supportsChannels(r)) {
-            return false;
-        }
-
         final int userId = UserHandle.getUserId(r.uid);
-        final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg,
-                PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                userId);
+        final ApplicationInfo applicationInfo = mPm.getApplicationInfoAsUser(r.pkg, 0, userId);
         if (applicationInfo.targetSdkVersion > Build.VERSION_CODES.N_MR1) {
             // O apps should not have the default channel.
             return false;
@@ -506,31 +500,6 @@
     }
 
     @Override
-    public boolean supportsChannels(String pkg, int uid) {
-        Record r = getOrCreateRecord(pkg, uid);
-
-        if (r == null) {
-            return false;
-        }
-
-        if (r.channels.size() == 1
-                && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
-            return false;
-        }
-
-        return true;
-    }
-
-    private boolean supportsChannels(Record r) {
-        if (r.channels.size() == 1
-                && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
-            return false;
-        }
-
-        return (r.channels.size() > 0);
-    }
-
-    @Override
     public void createNotificationChannelGroup(String pkg, int uid, NotificationChannelGroup group,
             boolean fromTargetApp) {
         Preconditions.checkNotNull(pkg);
@@ -602,10 +571,6 @@
         r.channels.put(channel.getId(), channel);
         MetricsLogger.action(getChannelLog(channel, pkg).setType(
                 MetricsProto.MetricsEvent.TYPE_OPEN));
-
-        // Remove Default Channel.
-        r.channels.remove(NotificationChannel.DEFAULT_CHANNEL_ID);
-
         updateConfig();
     }
 
@@ -702,7 +667,13 @@
         if (r == null) {
             return;
         }
-        r.channels.clear();
+        int N = r.channels.size() - 1;
+        for (int i = N; i >= 0; i--) {
+            String key = r.channels.keyAt(i);
+            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) {
+                r.channels.remove(key);
+            }
+        }
         updateConfig();
     }
 
@@ -1040,6 +1011,18 @@
         return packageChannels;
     }
 
+    public void onUserRemoved(int userId) {
+        synchronized (mRecords) {
+            int N = mRecords.size();
+            for (int i = N - 1; i >= 0 ; i--) {
+                Record record = mRecords.valueAt(i);
+                if (UserHandle.getUserId(record.uid) == userId) {
+                    mRecords.removeAt(i);
+                }
+            }
+        }
+    }
+
     public void onPackagesChanged(boolean removingPackage, int changeUserId, String[] pkgList,
             int[] uidList) {
         if (pkgList == null || pkgList.length == 0) {
@@ -1054,8 +1037,6 @@
                 final int uid = uidList[i];
                 synchronized (mRecords) {
                     mRecords.remove(recordKey(pkg, uid));
-                    // reset to default settings and re-add misc channel for pre-O apps
-                    getOrCreateRecord(pkg, uid);
                 }
                 mRestoredWithoutUids.remove(pkg);
                 updated = true;
diff --git a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
index 9d08004..09e9433 100644
--- a/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
+++ b/services/core/java/com/android/server/pm/EphemeralResolverConnection.java
@@ -43,6 +43,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.NoSuchElementException;
 import java.util.concurrent.TimeoutException;
 
 /**
@@ -206,7 +207,9 @@
 
     private void handleBinderDiedLocked() {
         if (mRemoteInstance != null) {
-            mRemoteInstance.asBinder().unlinkToDeath(this, 0 /*flags*/);
+            try {
+                mRemoteInstance.asBinder().unlinkToDeath(this, 0 /*flags*/);
+            } catch (NoSuchElementException ignore) { }
         }
         mRemoteInstance = null;
     }
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index c5cefc8..e6e4617 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -42,22 +42,20 @@
      * **************************************************************************/
     /** Application should be visible to everyone */
     public static final int DEXOPT_PUBLIC         = 1 << 1;
-    /** Application wants to run in VM safe mode */
-    public static final int DEXOPT_SAFEMODE       = 1 << 2;
     /** Application wants to allow debugging of its code */
-    public static final int DEXOPT_DEBUGGABLE     = 1 << 3;
+    public static final int DEXOPT_DEBUGGABLE     = 1 << 2;
     /** The system boot has finished */
-    public static final int DEXOPT_BOOTCOMPLETE   = 1 << 4;
+    public static final int DEXOPT_BOOTCOMPLETE   = 1 << 3;
     /** Hint that the dexopt type is profile-guided. */
-    public static final int DEXOPT_PROFILE_GUIDED = 1 << 5;
+    public static final int DEXOPT_PROFILE_GUIDED = 1 << 4;
     /** The compilation is for a secondary dex file. */
-    public static final int DEXOPT_SECONDARY_DEX  = 1 << 6;
+    public static final int DEXOPT_SECONDARY_DEX  = 1 << 5;
     /** Ignore the result of dexoptNeeded and force compilation. */
-    public static final int DEXOPT_FORCE          = 1 << 7;
+    public static final int DEXOPT_FORCE          = 1 << 6;
     /** Indicates that the dex file passed to dexopt in on CE storage. */
-    public static final int DEXOPT_STORAGE_CE     = 1 << 8;
+    public static final int DEXOPT_STORAGE_CE     = 1 << 7;
     /** Indicates that the dex file passed to dexopt in on DE storage. */
-    public static final int DEXOPT_STORAGE_DE     = 1 << 9;
+    public static final int DEXOPT_STORAGE_DE     = 1 << 8;
 
     // NOTE: keep in sync with installd
     public static final int FLAG_CLEAR_CACHE_ONLY = 1 << 8;
diff --git a/services/core/java/com/android/server/pm/InstantAppResolver.java b/services/core/java/com/android/server/pm/InstantAppResolver.java
index 624d8c9..f3c9cbb 100644
--- a/services/core/java/com/android/server/pm/InstantAppResolver.java
+++ b/services/core/java/com/android/server/pm/InstantAppResolver.java
@@ -125,6 +125,7 @@
                 final String packageName;
                 final String splitName;
                 final int versionCode;
+                final Intent failureIntent;
                 if (instantAppResolveInfoList != null && instantAppResolveInfoList.size() > 0) {
                     final AuxiliaryResolveInfo instantAppIntentInfo =
                             InstantAppResolver.filterInstantAppIntent(
@@ -135,18 +136,22 @@
                         packageName = instantAppIntentInfo.resolveInfo.getPackageName();
                         splitName = instantAppIntentInfo.splitName;
                         versionCode = instantAppIntentInfo.resolveInfo.getVersionCode();
+                        failureIntent = instantAppIntentInfo.failureIntent;
                     } else {
                         packageName = null;
                         splitName = null;
                         versionCode = -1;
+                        failureIntent = null;
                     }
                 } else {
                     packageName = null;
                     splitName = null;
                     versionCode = -1;
+                    failureIntent = null;
                 }
                 final Intent installerIntent = buildEphemeralInstallerIntent(
                         requestObj.origIntent,
+                        failureIntent,
                         requestObj.callingPackage,
                         requestObj.verificationBundle,
                         requestObj.resolvedType,
@@ -172,7 +177,9 @@
     /**
      * Builds and returns an intent to launch the instant installer.
      */
-    public static Intent buildEphemeralInstallerIntent(@NonNull Intent origIntent,
+    public static Intent buildEphemeralInstallerIntent(
+            @NonNull Intent origIntent,
+            @NonNull Intent failureIntent,
             @NonNull String callingPackage,
             @Nullable Bundle verificationBundle,
             @NonNull String resolvedType,
@@ -200,22 +207,21 @@
         // We have all of the data we need; just start the installer without a second phase
         if (!needsPhaseTwo) {
             // Intent that is launched if the package couldn't be installed for any reason.
-            final Intent failureIntent = new Intent(origIntent);
-            failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
-            failureIntent.setLaunchToken(token);
-            try {
-                final IIntentSender failureIntentTarget = ActivityManager.getService()
-                        .getIntentSender(
-                                ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
-                                null /*token*/, null /*resultWho*/, 1 /*requestCode*/,
-                                new Intent[] { failureIntent },
-                                new String[] { resolvedType },
-                                PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
-                                        | PendingIntent.FLAG_IMMUTABLE,
-                                null /*bOptions*/, userId);
-                intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE,
-                        new IntentSender(failureIntentTarget));
-            } catch (RemoteException ignore) { /* ignore; same process */ }
+            if (failureIntent != null) {
+                try {
+                    final IIntentSender failureIntentTarget = ActivityManager.getService()
+                            .getIntentSender(
+                                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
+                                    null /*token*/, null /*resultWho*/, 1 /*requestCode*/,
+                                    new Intent[] { failureIntent },
+                                    new String[] { resolvedType },
+                                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
+                                            | PendingIntent.FLAG_IMMUTABLE,
+                                    null /*bOptions*/, userId);
+                    intent.putExtra(Intent.EXTRA_EPHEMERAL_FAILURE,
+                            new IntentSender(failureIntentTarget));
+                } catch (RemoteException ignore) { /* ignore; same process */ }
+            }
 
             // Intent that is launched if the package was installed successfully.
             final Intent successIntent = new Intent(origIntent);
@@ -248,10 +254,13 @@
 
     private static AuxiliaryResolveInfo filterInstantAppIntent(
             List<InstantAppResolveInfo> instantAppResolveInfoList,
-            Intent intent, String resolvedType, int userId, String packageName,
+            Intent origIntent, String resolvedType, int userId, String packageName,
             InstantAppDigest digest, String token) {
         final int[] shaPrefix = digest.getDigestPrefix();
         final byte[][] digestBytes = digest.getDigestBytes();
+        final Intent failureIntent = new Intent(origIntent);
+        failureIntent.setFlags(failureIntent.getFlags() | Intent.FLAG_IGNORE_EPHEMERAL);
+        failureIntent.setLaunchToken(token);
         // Go in reverse order so we match the narrowest scope first.
         for (int i = shaPrefix.length - 1; i >= 0 ; --i) {
             for (InstantAppResolveInfo instantAppInfo : instantAppResolveInfoList) {
@@ -271,7 +280,8 @@
                     }
                     return new AuxiliaryResolveInfo(instantAppInfo,
                             new IntentFilter(Intent.ACTION_VIEW) /*intentFilter*/,
-                            null /*splitName*/, token, true /*needsPhase2*/);
+                            null /*splitName*/, token, true /*needsPhase2*/,
+                            null /*failureIntent*/);
                 }
                 // We have a domain match; resolve the filters to see if anything matches.
                 final PackageManagerService.EphemeralIntentResolver instantAppResolver =
@@ -286,12 +296,12 @@
                         final AuxiliaryResolveInfo intentInfo =
                                 new AuxiliaryResolveInfo(instantAppInfo,
                                         splitFilters.get(k), instantAppFilter.getSplitName(),
-                                        token, false /*needsPhase2*/);
+                                        token, false /*needsPhase2*/, failureIntent);
                         instantAppResolver.addFilter(intentInfo);
                     }
                 }
                 List<AuxiliaryResolveInfo> matchedResolveInfoList = instantAppResolver.queryIntent(
-                        intent, resolvedType, false /*defaultOnly*/, userId);
+                        origIntent, resolvedType, false /*defaultOnly*/, userId);
                 if (!matchedResolveInfoList.isEmpty()) {
                     if (DEBUG_EPHEMERAL) {
                         final AuxiliaryResolveInfo info = matchedResolveInfoList.get(0);
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index f94a56f..5ea6362 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -47,7 +47,6 @@
 import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
 import static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED;
 import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
-import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
 import static com.android.server.pm.Installer.DEXOPT_SECONDARY_DEX;
 import static com.android.server.pm.Installer.DEXOPT_FORCE;
 import static com.android.server.pm.Installer.DEXOPT_STORAGE_CE;
@@ -56,7 +55,9 @@
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
 
 import static com.android.server.pm.PackageManagerService.WATCHDOG_TIMEOUT;
-import static com.android.server.pm.PackageManagerServiceCompilerMapping.getNonProfileGuidedCompilerFilter;
+
+import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter;
+import static dalvik.system.DexFile.getSafeModeCompilerFilter;
 import static dalvik.system.DexFile.isProfileGuidedCompilerFilter;
 
 /**
@@ -381,13 +382,7 @@
         int flags = info.flags;
         boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
         if (vmSafeMode) {
-            // For the compilation, it doesn't really matter what we return here because installd
-            // will replace the filter with 'quicken' anyway.
-            // However, we return a non profile guided filter so that we simplify the logic of
-            // merging profiles.
-            // TODO(calin): safe mode path could be simplified if we pass 'quicken' from
-            //              here rather than letting installd decide on the filter.
-            return getNonProfileGuidedCompilerFilter(targetCompilerFilter);
+            return getSafeModeCompilerFilter(targetCompilerFilter);
         }
 
         if (isProfileGuidedCompilerFilter(targetCompilerFilter) && isUsedByOtherApps) {
@@ -408,7 +403,6 @@
 
     private int getDexFlags(ApplicationInfo info, String compilerFilter) {
         int flags = info.flags;
-        boolean vmSafeMode = (flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
         boolean debuggable = (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
         // Profile guide compiled oat files should not be public.
         boolean isProfileGuidedFilter = isProfileGuidedCompilerFilter(compilerFilter);
@@ -416,7 +410,6 @@
         int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
         int dexFlags =
                 (isPublic ? DEXOPT_PUBLIC : 0)
-                | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
                 | (debuggable ? DEXOPT_DEBUGGABLE : 0)
                 | profileFlag
                 | DEXOPT_BOOTCOMPLETE;
@@ -598,9 +591,6 @@
         if ((flags & DEXOPT_PUBLIC) == DEXOPT_PUBLIC) {
             flagsList.add("public");
         }
-        if ((flags & DEXOPT_SAFEMODE) == DEXOPT_SAFEMODE) {
-            flagsList.add("safemode");
-        }
         if ((flags & DEXOPT_SECONDARY_DEX) == DEXOPT_SECONDARY_DEX) {
             flagsList.add("secondary");
         }
@@ -634,9 +624,13 @@
 
         @Override
         protected int adjustDexoptNeeded(int dexoptNeeded) {
-            // Ensure compilation, no matter the current state.
-            // TODO: The return value is wrong when patchoat is needed.
-            return DexFile.DEX2OAT_FROM_SCRATCH;
+            if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
+                // Ensure compilation by pretending a compiler filter change on the
+                // apk/odex location (the reason for the '-'. A positive value means
+                // the 'oat' location).
+                return -DexFile.DEX2OAT_FOR_FILTER;
+            }
+            return dexoptNeeded;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c4f3b26..a40c071 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -97,11 +97,12 @@
 import static com.android.server.pm.InstructionSets.getPrimaryInstructionSet;
 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getCompilerFilterForReason;
 import static com.android.server.pm.PackageManagerServiceCompilerMapping.getDefaultCompilerFilter;
-import static com.android.server.pm.PackageManagerServiceCompilerMapping.getNonProfileGuidedCompilerFilter;
 import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_FAILURE;
 import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS;
 import static com.android.server.pm.PermissionsState.PERMISSION_OPERATION_SUCCESS_GIDS_CHANGED;
 
+import static dalvik.system.DexFile.getNonProfileGuidedCompilerFilter;
+
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -6499,11 +6500,12 @@
             String resolvedType, int flags, int userId) {
         // first, check to see if we've got an instant app already installed
         final boolean alreadyResolvedLocally = (flags & PackageManager.MATCH_INSTANT) != 0;
-        boolean localInstantAppAvailable = false;
+        ResolveInfo localInstantApp = null;
         boolean blockResolution = false;
         if (!alreadyResolvedLocally) {
             final List<ResolveInfo> instantApps = mActivities.queryIntent(intent, resolvedType,
                     flags
+                        | PackageManager.GET_RESOLVED_FILTER
                         | PackageManager.MATCH_INSTANT
                         | PackageManager.MATCH_VISIBLE_TO_INSTANT_APP_ONLY,
                     userId);
@@ -6530,7 +6532,7 @@
                         if (DEBUG_EPHEMERAL) {
                             Slog.v(TAG, "Found installed instant app; pkg: " + packageName);
                         }
-                        localInstantAppAvailable = true;
+                        localInstantApp = info;
                         break;
                     }
                 }
@@ -6538,17 +6540,29 @@
         }
         // no app installed, let's see if one's available
         AuxiliaryResolveInfo auxiliaryResponse = null;
-        if (!localInstantAppAvailable && !blockResolution) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
-            final InstantAppRequest requestObject = new InstantAppRequest(
-                    null /*responseObj*/, intent /*origIntent*/, resolvedType,
-                    null /*callingPackage*/, userId, null /*verificationBundle*/);
-            auxiliaryResponse =
-                    InstantAppResolver.doInstantAppResolutionPhaseOne(
-                            mContext, mInstantAppResolverConnection, requestObject);
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+        if (!blockResolution) {
+            if (localInstantApp == null) {
+                // we don't have an instant app locally, resolve externally
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "resolveEphemeral");
+                final InstantAppRequest requestObject = new InstantAppRequest(
+                        null /*responseObj*/, intent /*origIntent*/, resolvedType,
+                        null /*callingPackage*/, userId, null /*verificationBundle*/);
+                auxiliaryResponse =
+                        InstantAppResolver.doInstantAppResolutionPhaseOne(
+                                mContext, mInstantAppResolverConnection, requestObject);
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            } else {
+                // we have an instant application locally, but, we can't admit that since
+                // callers shouldn't be able to determine prior browsing. create a dummy
+                // auxiliary response so the downstream code behaves as if there's an
+                // instant application available externally. when it comes time to start
+                // the instant application, we'll do the right thing.
+                final ApplicationInfo ai = localInstantApp.activityInfo.applicationInfo;
+                auxiliaryResponse = new AuxiliaryResolveInfo(
+                        ai.packageName, null /*splitName*/, ai.versionCode, null /*failureIntent*/);
+            }
         }
-        if (localInstantAppAvailable || auxiliaryResponse != null) {
+        if (auxiliaryResponse != null) {
             if (DEBUG_EPHEMERAL) {
                 Slog.v(TAG, "Adding ephemeral installer to the ResolveInfo list");
             }
@@ -6568,7 +6582,7 @@
                 ephemeralInstaller.filter = new IntentFilter(intent.getAction());
                 ephemeralInstaller.filter.addDataPath(
                         intent.getData().getPath(), PatternMatcher.PATTERN_LITERAL);
-                ephemeralInstaller.instantAppAvailable = true;
+                ephemeralInstaller.isInstantAppAvailable = true;
                 result.add(ephemeralInstaller);
             }
         }
@@ -6703,7 +6717,7 @@
                     final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
                     installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
                             info.activityInfo.packageName, info.activityInfo.splitName,
-                            info.activityInfo.applicationInfo.versionCode);
+                            info.activityInfo.applicationInfo.versionCode, null /*failureIntent*/);
                     // make sure this resolver is the default
                     installerInfo.isDefault = true;
                     installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -7376,7 +7390,7 @@
                     final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
                     installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
                             info.serviceInfo.packageName, info.serviceInfo.splitName,
-                            info.serviceInfo.applicationInfo.versionCode);
+                            info.serviceInfo.applicationInfo.versionCode, null /*failureIntent*/);
                     // make sure this resolver is the default
                     installerInfo.isDefault = true;
                     installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -7497,7 +7511,7 @@
                     final ResolveInfo installerInfo = new ResolveInfo(mInstantAppInstallerInfo);
                     installerInfo.auxiliaryInfo = new AuxiliaryResolveInfo(
                             info.providerInfo.packageName, info.providerInfo.splitName,
-                            info.providerInfo.applicationInfo.versionCode);
+                            info.providerInfo.applicationInfo.versionCode, null /*failureIntent*/);
                     // make sure this resolver is the default
                     installerInfo.isDefault = true;
                     installerInfo.match = IntentFilter.MATCH_CATEGORY_SCHEME_SPECIFIC_PART
@@ -18541,11 +18555,6 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.DELETE_PACKAGES, null);
         synchronized (mPackages) {
-            PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (ps == null) {
-                Log.i(TAG, "Package doesn't exist in set block uninstall " + packageName);
-                return false;
-            }
             // Cannot block uninstall of static shared libs as they are
             // considered a part of the using app (emulating static linking).
             // Also static libs are installed always on internal storage.
@@ -18555,12 +18564,7 @@
                         + " providing static shared library: " + pkg.staticSharedLibName);
                 return false;
             }
-            if (!ps.getInstalled(userId)) {
-                // Can't block uninstall for an app that is not installed or enabled.
-                Log.i(TAG, "Package not installed in set block uninstall " + packageName);
-                return false;
-            }
-            ps.setBlockUninstall(blockUninstall, userId);
+            mSettings.setBlockUninstallLPw(userId, packageName, blockUninstall);
             mSettings.writePackageRestrictionsLPr(userId);
         }
         return true;
@@ -18569,12 +18573,7 @@
     @Override
     public boolean getBlockUninstallForUser(String packageName, int userId) {
         synchronized (mPackages) {
-            PackageSetting ps = mSettings.mPackages.get(packageName);
-            if (ps == null) {
-                Log.i(TAG, "Package doesn't exist in get block uninstall " + packageName);
-                return false;
-            }
-            return ps.getBlockUninstall(userId);
+            return mSettings.getBlockUninstallLPr(userId, packageName);
         }
     }
 
@@ -18781,7 +18780,6 @@
                     null /*lastDisableAppCaller*/,
                     null /*enabledComponents*/,
                     null /*disabledComponents*/,
-                    false /*blockUninstall*/,
                     ps.readUserState(nextUserId).domainVerificationStatus,
                     0, PackageManager.INSTALL_REASON_UNKNOWN);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 284bb3f..ec248f5 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -111,11 +111,4 @@
 
         return value;
     }
-
-    /**
-     * Return the non-profile-guided filter corresponding to the given filter.
-     */
-    public static String getNonProfileGuidedCompilerFilter(String filter) {
-        return DexFile.getNonProfileGuidedCompilerFilter(filter);
-    }
 }
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index dfed72f..14f65eb 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -402,14 +402,6 @@
         modifyUserState(userId).suspended = suspended;
     }
 
-    boolean getBlockUninstall(int userId) {
-        return readUserState(userId).blockUninstall;
-    }
-
-    void setBlockUninstall(boolean blockUninstall, int userId) {
-        modifyUserState(userId).blockUninstall = blockUninstall;
-    }
-
     boolean getInstantApp(int userId) {
         return readUserState(userId).instantApp;
     }
@@ -421,8 +413,8 @@
     void setUserState(int userId, long ceDataInode, int enabled, boolean installed, boolean stopped,
             boolean notLaunched, boolean hidden, boolean suspended, boolean instantApp,
             String lastDisableAppCaller, ArraySet<String> enabledComponents,
-            ArraySet<String> disabledComponents, boolean blockUninstall,
-            int domainVerifState, int linkGeneration, int installReason) {
+            ArraySet<String> disabledComponents, int domainVerifState,
+            int linkGeneration, int installReason) {
         PackageUserState state = modifyUserState(userId);
         state.ceDataInode = ceDataInode;
         state.enabled = enabled;
@@ -434,7 +426,6 @@
         state.lastDisableAppCaller = lastDisableAppCaller;
         state.enabledComponents = enabledComponents;
         state.disabledComponents = disabledComponents;
-        state.blockUninstall = blockUninstall;
         state.domainVerificationStatus = domainVerifState;
         state.appLinkGeneration = linkGeneration;
         state.installReason = installReason;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index cea031e..44bcff2 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -186,6 +186,8 @@
     private static final String TAG_PERMISSIONS = "perms";
     private static final String TAG_CHILD_PACKAGE = "child-package";
     private static final String TAG_USES_STATIC_LIB = "uses-static-lib";
+    private static final String TAG_BLOCK_UNINSTALL_PACKAGES = "block-uninstall-packages";
+    private static final String TAG_BLOCK_UNINSTALL = "block-uninstall";
 
     private static final String TAG_PERSISTENT_PREFERRED_ACTIVITIES =
             "persistent-preferred-activities";
@@ -215,6 +217,8 @@
     // New name for the above attribute.
     private static final String ATTR_HIDDEN = "hidden";
     private static final String ATTR_SUSPENDED = "suspended";
+    // Legacy, uninstall blocks are stored separately.
+    @Deprecated
     private static final String ATTR_BLOCK_UNINSTALL = "blockUninstall";
     private static final String ATTR_ENABLED = "enabled";
     private static final String ATTR_ENABLED_CALLER = "enabledCaller";
@@ -271,6 +275,9 @@
     private final ArrayMap<String, PackageSetting> mDisabledSysPackages =
         new ArrayMap<String, PackageSetting>();
 
+    /** List of packages that are blocked for uninstall for specific users */
+    private final SparseArray<ArraySet<String>> mBlockUninstallPackages = new SparseArray<>();
+
     // Set of restored intent-filter verification states
     private final ArrayMap<String, IntentFilterVerificationInfo> mRestoredIntentFilterVerifications =
             new ArrayMap<String, IntentFilterVerificationInfo>();
@@ -756,7 +763,6 @@
                                 null /*lastDisableAppCaller*/,
                                 null /*enabledComponents*/,
                                 null /*disabledComponents*/,
-                                false /*blockUninstall*/,
                                 INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
                                 0, PackageManager.INSTALL_REASON_UNKNOWN);
                     }
@@ -1614,6 +1620,34 @@
         }
     }
 
+    void readBlockUninstallPackagesLPw(XmlPullParser parser, int userId)
+            throws XmlPullParserException, IOException {
+        int outerDepth = parser.getDepth();
+        int type;
+        ArraySet<String> packages = new ArraySet<>();
+        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                continue;
+            }
+            String tagName = parser.getName();
+            if (tagName.equals(TAG_BLOCK_UNINSTALL)) {
+                String packageName = parser.getAttributeValue(null, ATTR_PACKAGE_NAME);
+                packages.add(packageName);
+            } else {
+                String msg = "Unknown element under " +  TAG_BLOCK_UNINSTALL_PACKAGES + ": " +
+                        parser.getName();
+                PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+                XmlUtils.skipCurrentTag(parser);
+            }
+        }
+        if (packages.isEmpty()) {
+            mBlockUninstallPackages.remove(userId);
+        } else {
+            mBlockUninstallPackages.put(userId, packages);
+        }
+    }
+
     void readPackageRestrictionsLPr(int userId) {
         if (DEBUG_MU) {
             Log.i(TAG, "Reading package restrictions for user=" + userId);
@@ -1662,7 +1696,6 @@
                                 null /*lastDisableAppCaller*/,
                                 null /*enabledComponents*/,
                                 null /*disabledComponents*/,
-                                false /*blockUninstall*/,
                                 INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED,
                                 0, PackageManager.INSTALL_REASON_UNKNOWN);
                     }
@@ -1768,9 +1801,12 @@
                         }
                     }
 
+                    if (blockUninstall) {
+                        setBlockUninstallLPw(userId, name, true);
+                    }
                     ps.setUserState(userId, ceDataInode, enabled, installed, stopped, notLaunched,
                             hidden, suspended, instantApp, enabledCaller, enabledComponents,
-                            disabledComponents, blockUninstall, verifState, linkGeneration,
+                            disabledComponents, verifState, linkGeneration,
                             installReason);
                 } else if (tagName.equals("preferred-activities")) {
                     readPreferredActivitiesLPw(parser, userId);
@@ -1780,6 +1816,8 @@
                     readCrossProfileIntentFiltersLPw(parser, userId);
                 } else if (tagName.equals(TAG_DEFAULT_APPS)) {
                     readDefaultAppsLPw(parser, userId);
+                } else if (tagName.equals(TAG_BLOCK_UNINSTALL_PACKAGES)) {
+                    readBlockUninstallPackagesLPw(parser, userId);
                 } else {
                     Slog.w(PackageManagerService.TAG, "Unknown element under <stopped-packages>: "
                           + parser.getName());
@@ -1806,6 +1844,30 @@
         }
     }
 
+    void setBlockUninstallLPw(int userId, String packageName, boolean blockUninstall) {
+        ArraySet<String> packages = mBlockUninstallPackages.get(userId);
+        if (blockUninstall) {
+            if (packages == null) {
+                packages = new ArraySet<String>();
+                mBlockUninstallPackages.put(userId, packages);
+            }
+            packages.add(packageName);
+        } else if (packages != null) {
+            packages.remove(packageName);
+            if (packages.isEmpty()) {
+                mBlockUninstallPackages.remove(userId);
+            }
+        }
+    }
+
+    boolean getBlockUninstallLPr(int userId, String packageName) {
+        ArraySet<String> packages = mBlockUninstallPackages.get(userId);
+        if (packages == null) {
+            return false;
+        }
+        return packages.contains(packageName);
+    }
+
     private ArraySet<String> readComponentsLPr(XmlPullParser parser)
             throws IOException, XmlPullParserException {
         ArraySet<String> components = null;
@@ -1976,6 +2038,20 @@
         serializer.endTag(null, TAG_DEFAULT_APPS);
     }
 
+    void writeBlockUninstallPackagesLPr(XmlSerializer serializer, int userId)
+            throws IOException  {
+        ArraySet<String> packages = mBlockUninstallPackages.get(userId);
+        if (packages != null) {
+            serializer.startTag(null, TAG_BLOCK_UNINSTALL_PACKAGES);
+            for (int i = 0; i < packages.size(); i++) {
+                 serializer.startTag(null, TAG_BLOCK_UNINSTALL);
+                 serializer.attribute(null, ATTR_PACKAGE_NAME, packages.valueAt(i));
+                 serializer.endTag(null, TAG_BLOCK_UNINSTALL);
+            }
+            serializer.endTag(null, TAG_BLOCK_UNINSTALL_PACKAGES);
+        }
+    }
+
     void writePackageRestrictionsLPr(int userId) {
         if (DEBUG_MU) {
             Log.i(TAG, "Writing package restrictions for user=" + userId);
@@ -2038,9 +2114,6 @@
                 if (ustate.suspended) {
                     serializer.attribute(null, ATTR_SUSPENDED, "true");
                 }
-                if (ustate.blockUninstall) {
-                    serializer.attribute(null, ATTR_BLOCK_UNINSTALL, "true");
-                }
                 if (ustate.instantApp) {
                     serializer.attribute(null, ATTR_INSTANT_APP, "true");
                 }
@@ -2091,6 +2164,7 @@
             writePersistentPreferredActivitiesLPr(serializer, userId);
             writeCrossProfileIntentFiltersLPr(serializer, userId);
             writeDefaultAppsLPr(serializer, userId);
+            writeBlockUninstallPackagesLPr(serializer, userId);
 
             serializer.endTag(null, TAG_PACKAGE_RESTRICTIONS);
 
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index bed8f1a..7f0528a 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1611,6 +1611,11 @@
      */
     private void fixUpIncomingShortcutInfo(@NonNull ShortcutInfo shortcut, boolean forUpdate,
             boolean forPinRequest) {
+        if (shortcut.isReturnedByServer()) {
+            Log.w(TAG,
+                    "Re-publishing ShortcutInfo returned by server is not supported."
+                    + " Some information such as icon may lost from shortcut.");
+        }
         Preconditions.checkNotNull(shortcut, "Null shortcut detected");
         if (shortcut.getActivity() != null) {
             Preconditions.checkState(
@@ -1670,6 +1675,13 @@
         }
     }
 
+    private List<ShortcutInfo> setReturnedByServer(List<ShortcutInfo> shortcuts) {
+        for (int i = shortcuts.size() - 1; i >= 0; i--) {
+            shortcuts.get(i).setReturnedByServer();
+        }
+        return shortcuts;
+    }
+
     // === APIs ===
 
     @Override
@@ -2049,7 +2061,7 @@
         final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId);
         ps.findAll(ret, query, cloneFlags);
 
-        return new ParceledListSlice<>(ret);
+        return new ParceledListSlice<>(setReturnedByServer(ret));
     }
 
     @Override
@@ -2406,7 +2418,7 @@
                     });
                 }
             }
-            return ret;
+            return setReturnedByServer(ret);
         }
 
         private void getShortcutsInnerLocked(int launcherUserId, @NonNull String callingPackage,
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 4a8232d..be50eee 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -62,6 +62,7 @@
     // Maps package name to code locations.
     // It caches the code locations for the installed packages. This allows for
     // faster lookups (no locks) when finding what package owns the dex file.
+    @GuardedBy("mPackageCodeLocationsCache")
     private final Map<String, PackageCodeLocations> mPackageCodeLocationsCache;
 
     // PackageDexUsage handles the actual I/O operations. It is responsible to
@@ -206,7 +207,7 @@
         // In case there was an update, write the package use info to disk async.
         // Note that we do the writing here and not in PackageDexUsage in order to be
         // consistent with other methods in DexManager (e.g. reconcileSecondaryDexFiles performs
-        // multiple updates in PackaeDexUsage before writing it).
+        // multiple updates in PackageDexUsage before writing it).
         if (mPackageDexUsage.clearUsedByOtherApps(packageName)) {
             mPackageDexUsage.maybeWriteAsync();
         }
@@ -226,7 +227,7 @@
         // In case there was an update, write the package use info to disk async.
         // Note that we do the writing here and not in PackageDexUsage in order to be
         // consistent with other methods in DexManager (e.g. reconcileSecondaryDexFiles performs
-        // multiple updates in PackaeDexUsage before writing it).
+        // multiple updates in PackageDexUsage before writing it).
         if (updated) {
             mPackageDexUsage.maybeWriteAsync();
         }
@@ -245,17 +246,22 @@
 
     private void cachePackageCodeLocation(String packageName, String baseCodePath,
             String[] splitCodePaths, String[] dataDirs, int userId) {
-        PackageCodeLocations pcl = putIfAbsent(mPackageCodeLocationsCache, packageName,
-                new PackageCodeLocations(packageName, baseCodePath, splitCodePaths));
-        pcl.updateCodeLocation(baseCodePath, splitCodePaths);
-        if (dataDirs != null) {
-            for (String dataDir : dataDirs) {
-                // The set of data dirs includes deviceProtectedDataDir and
-                // credentialProtectedDataDir which might be null for shared
-                // libraries. Currently we don't track these but be lenient
-                // and check in case we ever decide to store their usage data.
-                if (dataDir != null) {
-                    pcl.mergeAppDataDirs(dataDir, userId);
+        synchronized (mPackageCodeLocationsCache) {
+            PackageCodeLocations pcl = putIfAbsent(mPackageCodeLocationsCache, packageName,
+                    new PackageCodeLocations(packageName, baseCodePath, splitCodePaths));
+            // TODO(calin): We are forced to extend the scope of this synchronization because
+            // the values of the cache (PackageCodeLocations) are updated in place.
+            // Make PackageCodeLocations immutable to simplify the synchronization reasoning.
+            pcl.updateCodeLocation(baseCodePath, splitCodePaths);
+            if (dataDirs != null) {
+                for (String dataDir : dataDirs) {
+                    // The set of data dirs includes deviceProtectedDataDir and
+                    // credentialProtectedDataDir which might be null for shared
+                    // libraries. Currently we don't track these but be lenient
+                    // and check in case we ever decide to store their usage data.
+                    if (dataDir != null) {
+                        pcl.mergeAppDataDirs(dataDir, userId);
+                    }
                 }
             }
         }
@@ -527,10 +533,12 @@
         // The loadingPackage does not own the dex file.
         // Perform a reverse look-up in the cache to detect if any package has ownership.
         // Note that we can have false negatives if the cache falls out of date.
-        for (PackageCodeLocations pcl : mPackageCodeLocationsCache.values()) {
-            outcome = pcl.searchDex(dexPath, userId);
-            if (outcome != DEX_SEARCH_NOT_FOUND) {
-                return new DexSearchResult(pcl.mPackageName, outcome);
+        synchronized (mPackageCodeLocationsCache) {
+            for (PackageCodeLocations pcl : mPackageCodeLocationsCache.values()) {
+                outcome = pcl.searchDex(dexPath, userId);
+                if (outcome != DEX_SEARCH_NOT_FOUND) {
+                    return new DexSearchResult(pcl.mPackageName, outcome);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 42eebe1..857025d 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -584,6 +584,8 @@
     boolean mTranslucentDecorEnabled = true;
     boolean mUseTvRouting;
 
+    private boolean mHandleVolumeKeysInWM;
+
     int mPointerLocationMode = 0; // guarded by mLock
 
     // The last window we were told about in focusChanged.
@@ -780,6 +782,10 @@
     private boolean mBugreportTvKey2Pressed;
     private boolean mBugreportTvScheduled;
 
+    private boolean mAccessibilityTvKey1Pressed;
+    private boolean mAccessibilityTvKey2Pressed;
+    private boolean mAccessibilityTvScheduled;
+
     /* The number of steps between min and max brightness */
     private static final int BRIGHTNESS_STEPS = 10;
 
@@ -824,6 +830,7 @@
     private static final int MSG_BACK_DELAYED_PRESS = 20;
     private static final int MSG_ACCESSIBILITY_SHORTCUT = 21;
     private static final int MSG_BUGREPORT_TV = 22;
+    private static final int MSG_ACCESSIBILITY_TV = 23;
 
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -905,6 +912,11 @@
                 case MSG_BUGREPORT_TV:
                     takeBugreport();
                     break;
+                case MSG_ACCESSIBILITY_TV:
+                    if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable(false)) {
+                        accessibilityShortcutActivated();
+                    }
+                    break;
             }
         }
     }
@@ -1928,6 +1940,9 @@
 
         mUseTvRouting = AudioSystem.getPlatformType(mContext) == AudioSystem.PLATFORM_TELEVISION;
 
+        mHandleVolumeKeysInWM = mContext.getResources().getBoolean(
+                com.android.internal.R.bool.config_handleVolumeKeysInWindowManager);
+
         readConfigurationDependentBehaviors();
 
         mAccessibilityManager = (AccessibilityManager) context.getSystemService(
@@ -3319,6 +3334,11 @@
             if (!down) {
                 cancelPreloadRecentApps();
 
+                if (mHasFeatureLeanback) {
+                    // Clear flags
+                    mAccessibilityTvKey2Pressed = down;
+                }
+
                 mHomePressed = false;
                 if (mHomeConsumed) {
                     mHomeConsumed = false;
@@ -3373,6 +3393,13 @@
                     preloadRecentApps();
                 }
             } else if ((event.getFlags() & KeyEvent.FLAG_LONG_PRESS) != 0) {
+                if (mHasFeatureLeanback) {
+                    mAccessibilityTvKey2Pressed = down;
+                    if (interceptAccessibilityGestureTv()) {
+                        return -1;
+                    }
+                }
+
                 if (!keyguardOn) {
                     handleLongPressOnHome(event.getDeviceId());
                 }
@@ -3522,16 +3549,28 @@
         } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP
                 || keyCode == KeyEvent.KEYCODE_VOLUME_DOWN
                 || keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
-            if (mUseTvRouting) {
-                // On TVs volume keys never go to the foreground app.
+            if (mUseTvRouting || mHandleVolumeKeysInWM) {
+                // On TVs or when the configuration is enabled, volume keys never
+                // go to the foreground app.
                 dispatchDirectAudioEvent(event);
                 return -1;
             }
+
+            // If the device is in Vr mode, drop the volume keys and don't
+            // forward it to the application/dispatch the audio event.
+            if (mPersistentVrModeEnabled) {
+                return -1;
+            }
         } else if (keyCode == KeyEvent.KEYCODE_TAB && event.isMetaPressed()) {
             // Pass through keyboard navigation keys.
             return 0;
         } else if (mHasFeatureLeanback && interceptBugreportGestureTv(keyCode, down)) {
             return -1;
+        } else if (mHasFeatureLeanback && keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
+            mAccessibilityTvKey1Pressed = down;
+            if (interceptAccessibilityGestureTv()) {
+                return -1;
+            }
         }
 
         // Toggle Caps Lock on META-ALT.
@@ -3750,6 +3789,25 @@
         return mBugreportTvScheduled;
     }
 
+    /**
+     * TV only: recognizes a remote control gesture as Accessibility shortcut.
+     * Shortcut: Long press (HOME + DPAD_CENTER)
+     */
+    private boolean interceptAccessibilityGestureTv() {
+        if (mAccessibilityTvKey1Pressed && mAccessibilityTvKey2Pressed) {
+            if (!mAccessibilityTvScheduled) {
+                mAccessibilityTvScheduled = true;
+                Message msg = Message.obtain(mHandler, MSG_ACCESSIBILITY_TV);
+                msg.setAsynchronous(true);
+                mHandler.sendMessage(msg);
+            }
+        } else if (mAccessibilityTvScheduled) {
+            mHandler.removeMessages(MSG_ACCESSIBILITY_TV);
+            mAccessibilityTvScheduled = false;
+        }
+        return mAccessibilityTvScheduled;
+    }
+
     private void takeBugreport() {
         if ("1".equals(SystemProperties.get("ro.debuggable"))
                 || Settings.Global.getInt(mContext.getContentResolver(),
@@ -5427,7 +5485,8 @@
                 // Maintain fullscreen layout until incoming animation is complete.
                 topIsFullscreen = mTopIsFullscreen && mStatusBar.isAnimatingLw();
                 // Transient status bar on the lockscreen is not allowed
-                if (mForceStatusBarFromKeyguard && mStatusBarController.isTransientShowing()) {
+                if ((mForceStatusBarFromKeyguard || statusBarExpanded)
+                        && mStatusBarController.isTransientShowing()) {
                     mStatusBarController.updateVisibilityLw(false /*transientAllowed*/,
                             mLastSystemUiFlags, mLastSystemUiFlags);
                 }
@@ -5911,8 +5970,8 @@
                         }
                     }
                 }
-                if (mUseTvRouting) {
-                    // On TVs, defer special key handlings to
+                if (mUseTvRouting || mHandleVolumeKeysInWM) {
+                    // Defer special key handlings to
                     // {@link interceptKeyBeforeDispatching()}.
                     result |= ACTION_PASS_TO_USER;
                 } else if ((result & ACTION_PASS_TO_USER) == 0) {
@@ -8235,6 +8294,14 @@
         pw.print(prefix); pw.print("mDemoHdmiRotation="); pw.print(mDemoHdmiRotation);
                 pw.print(" mDemoHdmiRotationLock="); pw.println(mDemoHdmiRotationLock);
         pw.print(prefix); pw.print("mUndockedHdmiRotation="); pw.println(mUndockedHdmiRotation);
+        if (mHasFeatureLeanback) {
+            pw.print(prefix);
+            pw.print("mAccessibilityTvKey1Pressed="); pw.println(mAccessibilityTvKey1Pressed);
+            pw.print(prefix);
+            pw.print("mAccessibilityTvKey2Pressed="); pw.println(mAccessibilityTvKey2Pressed);
+            pw.print(prefix);
+            pw.print("mAccessibilityTvScheduled="); pw.println(mAccessibilityTvScheduled);
+        }
 
         mGlobalKeyManager.dump(prefix, pw);
         mStatusBarController.dump(pw, prefix);
diff --git a/services/core/java/com/android/server/radio/Tuner.java b/services/core/java/com/android/server/radio/Tuner.java
index a06d8c6..85f5e56 100644
--- a/services/core/java/com/android/server/radio/Tuner.java
+++ b/services/core/java/com/android/server/radio/Tuner.java
@@ -32,11 +32,14 @@
     private final long mNativeContext;
 
     private final Object mLock = new Object();
+    private boolean mIsMuted = false;
     private int mRegion;  // TODO(b/36863239): find better solution to manage regions
+    private final boolean mWithAudio;
 
-    Tuner(@NonNull ITunerCallback clientCallback, int region) {
+    Tuner(@NonNull ITunerCallback clientCallback, int halRev, int region, boolean withAudio) {
         mRegion = region;
-        mNativeContext = nativeInit(clientCallback);
+        mWithAudio = withAudio;
+        mNativeContext = nativeInit(clientCallback, halRev);
     }
 
     @Override
@@ -45,7 +48,7 @@
         super.finalize();
     }
 
-    private native long nativeInit(@NonNull ITunerCallback clientCallback);
+    private native long nativeInit(@NonNull ITunerCallback clientCallback, int halRev);
     private native void nativeFinalize(long nativeContext);
     private native void nativeClose(long nativeContext);
 
@@ -53,6 +56,11 @@
             @NonNull RadioManager.BandConfig config);
     private native RadioManager.BandConfig nativeGetConfiguration(long nativeContext, int region);
 
+    private native void nativeStep(long nativeContext, boolean directionDown, boolean skipSubChannel);
+    private native void nativeScan(long nativeContext, boolean directionDown, boolean skipSubChannel);
+    private native void nativeTune(long nativeContext, int channel, int subChannel);
+    private native void nativeCancel(long nativeContext);
+
     @Override
     public void close() {
         synchronized (mLock) {
@@ -86,4 +94,57 @@
         Slog.d(TAG, "getProgramInformation()");
         return RadioManager.STATUS_INVALID_OPERATION;
     }
+
+    @Override
+    public void setMuted(boolean mute) {
+        if (!mWithAudio) {
+            throw new IllegalStateException("Can't operate on mute - no audio requested");
+        }
+        synchronized (mLock) {
+            if (mIsMuted == mute) return;
+            mIsMuted = mute;
+
+            // TODO(b/34348946): notifify audio policy manager of media activity on radio audio
+            // device. This task is pulled directly from previous implementation of native service.
+        }
+    }
+
+    @Override
+    public boolean isMuted() {
+        if (!mWithAudio) {
+            Slog.w(TAG, "Tuner did not request audio, pretending it was muted");
+            return true;
+        }
+        synchronized (mLock) {
+            return mIsMuted;
+        }
+    }
+
+    @Override
+    public void step(boolean directionDown, boolean skipSubChannel) {
+        synchronized (mLock) {
+            nativeStep(mNativeContext, directionDown, skipSubChannel);
+        }
+    }
+
+    @Override
+    public void scan(boolean directionDown, boolean skipSubChannel) {
+        synchronized (mLock) {
+            nativeScan(mNativeContext, directionDown, skipSubChannel);
+        }
+    }
+
+    @Override
+    public void tune(int channel, int subChannel) {
+        synchronized (mLock) {
+            nativeTune(mNativeContext, channel, subChannel);
+        }
+    }
+
+    @Override
+    public void cancel() {
+        synchronized (mLock) {
+            nativeCancel(mNativeContext);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/storage/DiskStatsLoggingService.java b/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
index 4035ade..9a08ac3 100644
--- a/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
+++ b/services/core/java/com/android/server/storage/DiskStatsLoggingService.java
@@ -73,13 +73,13 @@
         final int userId = UserHandle.myUserId();
         UserEnvironment environment = new UserEnvironment(userId);
         LogRunnable task = new LogRunnable();
-        task.setRootDirectory(environment.getExternalStorageDirectory());
         task.setDownloadsDirectory(
                 environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS));
         task.setSystemSize(FileCollector.getSystemSize(this));
         task.setLogOutputFile(new File(DUMPSYS_CACHE_PATH));
         task.setAppCollector(collector);
         task.setJobService(this, params);
+        task.setContext(this);
         AsyncTask.execute(task);
         return true;
     }
@@ -106,7 +106,8 @@
     }
 
     private static boolean isCharging(Context context) {
-        BatteryManager batteryManager = context.getSystemService(BatteryManager.class);
+        BatteryManager batteryManager =
+                (BatteryManager) context.getSystemService(Context.BATTERY_SERVICE);
         if (batteryManager != null) {
             return batteryManager.isCharging();
         }
@@ -127,14 +128,10 @@
         private JobParameters mParams;
         private AppCollector mCollector;
         private File mOutputFile;
-        private File mRootDirectory;
         private File mDownloadsDirectory;
+        private Context mContext;
         private long mSystemSize;
 
-        public void setRootDirectory(File file) {
-            mRootDirectory = file;
-        }
-
         public void setDownloadsDirectory(File file) {
             mDownloadsDirectory = file;
         }
@@ -151,14 +148,25 @@
             mSystemSize = size;
         }
 
+        public void setContext(Context context) {
+            mContext = context;
+        }
+
         public void setJobService(JobService jobService, JobParameters params) {
             mJobService = jobService;
             mParams = params;
         }
 
         public void run() {
-            FileCollector.MeasurementResult mainCategories =
-                    FileCollector.getMeasurementResult(mRootDirectory);
+            FileCollector.MeasurementResult mainCategories;
+            try {
+                mainCategories = FileCollector.getMeasurementResult(mContext);
+            } catch (IllegalStateException e) {
+                // This can occur if installd has an issue.
+                Log.e(TAG, "Error while measuring storage", e);
+                finishJob(true);
+                return;
+            }
             FileCollector.MeasurementResult downloads =
                     FileCollector.getMeasurementResult(mDownloadsDirectory);
 
@@ -168,12 +176,10 @@
                 needsReschedule = false;
                 logToFile(mainCategories, downloads, stats, mSystemSize);
             } else {
-                Log.w("TAG", "Timed out while fetching package stats.");
+                Log.w(TAG, "Timed out while fetching package stats.");
             }
 
-            if (mJobService != null) {
-                mJobService.jobFinished(mParams, needsReschedule);
-            }
+            finishJob(needsReschedule);
         }
 
         private void logToFile(MeasurementResult mainCategories, MeasurementResult downloads,
@@ -187,5 +193,11 @@
                 Log.e(TAG, "Exception while writing opportunistic disk file cache.", e);
             }
         }
+
+        private void finishJob(boolean needsReschedule) {
+            if (mJobService != null) {
+                mJobService.jobFinished(mParams, needsReschedule);
+            }
+        }
     }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/storage/FileCollector.java b/services/core/java/com/android/server/storage/FileCollector.java
index 90f9f139..0c119a7 100644
--- a/services/core/java/com/android/server/storage/FileCollector.java
+++ b/services/core/java/com/android/server/storage/FileCollector.java
@@ -17,13 +17,17 @@
 package com.android.server.storage;
 
 import android.annotation.IntDef;
+import android.app.usage.ExternalStorageStats;
+import android.app.usage.StorageStatsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
+import android.os.UserHandle;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 import android.util.ArrayMap;
 
 import java.io.File;
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.Map;
@@ -154,15 +158,46 @@
     }
 
     /**
+     * Returns the file categorization result for the primary internal storage UUID.
+     *
+     * @param context
+     */
+    public static MeasurementResult getMeasurementResult(Context context) {
+        MeasurementResult result = new MeasurementResult();
+        StorageStatsManager ssm =
+                (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE);
+        ExternalStorageStats stats = null;
+        try {
+            stats =
+                    ssm.queryExternalStatsForUser(
+                            StorageManager.UUID_PRIVATE_INTERNAL,
+                            UserHandle.of(context.getUserId()));
+            result.imagesSize = stats.getImageBytes();
+            result.videosSize = stats.getVideoBytes();
+            result.audioSize = stats.getAudioBytes();
+            result.miscSize =
+                    stats.getTotalBytes()
+                            - result.imagesSize
+                            - result.videosSize
+                            - result.audioSize;
+        } catch (IOException e) {
+            throw new IllegalStateException("Could not query storage");
+        }
+
+        return result;
+    }
+
+    /**
      * Returns the size of a system for a given context. This is done by finding the difference
      * between the shared data and the total primary storage size.
+     *
      * @param context Context to use to get storage information.
      */
     public static long getSystemSize(Context context) {
         PackageManager pm = context.getPackageManager();
         VolumeInfo primaryVolume = pm.getPrimaryStorageCurrentVolume();
 
-        StorageManager sm = context.getSystemService(StorageManager.class);
+        StorageManager sm = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
         VolumeInfo shared = sm.findEmulatedForPrivate(primaryVolume);
         if (shared == null) {
             return 0;
diff --git a/services/core/java/com/android/server/timezone/CheckToken.java b/services/core/java/com/android/server/timezone/CheckToken.java
new file mode 100644
index 0000000..5128360
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/CheckToken.java
@@ -0,0 +1,98 @@
+/*
+ * 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.server.timezone;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * A deserialized version of the byte[] sent to the time zone update application to identify a
+ * triggered time zone update check. It encodes the optimistic lock ID used to detect
+ * concurrent checks and the minimal package versions that will have been checked.
+ */
+final class CheckToken {
+
+    final int mOptimisticLockId;
+    final PackageVersions mPackageVersions;
+
+    CheckToken(int optimisticLockId, PackageVersions packageVersions) {
+        this.mOptimisticLockId = optimisticLockId;
+
+        if (packageVersions == null) {
+            throw new NullPointerException("packageVersions == null");
+        }
+        this.mPackageVersions = packageVersions;
+    }
+
+    byte[] toByteArray() {
+        ByteArrayOutputStream baos = new ByteArrayOutputStream(12 /* (3 * sizeof(int)) */);
+        try (DataOutputStream dos = new DataOutputStream(baos)) {
+            dos.writeInt(mOptimisticLockId);
+            dos.writeInt(mPackageVersions.mUpdateAppVersion);
+            dos.writeInt(mPackageVersions.mDataAppVersion);
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to write into a ByteArrayOutputStream", e);
+        }
+        return baos.toByteArray();
+    }
+
+    static CheckToken fromByteArray(byte[] tokenBytes) throws IOException {
+        ByteArrayInputStream bais = new ByteArrayInputStream(tokenBytes);
+        try (DataInputStream dis = new DataInputStream(bais)) {
+            int versionId = dis.readInt();
+            int updateAppVersion = dis.readInt();
+            int dataAppVersion = dis.readInt();
+            return new CheckToken(versionId, new PackageVersions(updateAppVersion, dataAppVersion));
+        }
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        CheckToken checkToken = (CheckToken) o;
+
+        if (mOptimisticLockId != checkToken.mOptimisticLockId) {
+            return false;
+        }
+        return mPackageVersions.equals(checkToken.mPackageVersions);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mOptimisticLockId;
+        result = 31 * result + mPackageVersions.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "Token{" +
+                "mOptimisticLockId=" + mOptimisticLockId +
+                ", mPackageVersions=" + mPackageVersions +
+                '}';
+    }
+}
diff --git a/core/java/android/app/CompatibilityDisplayProperties.aidl b/services/core/java/com/android/server/timezone/ClockHelper.java
similarity index 75%
copy from core/java/android/app/CompatibilityDisplayProperties.aidl
copy to services/core/java/com/android/server/timezone/ClockHelper.java
index 626a63e..353728a 100644
--- a/core/java/android/app/CompatibilityDisplayProperties.aidl
+++ b/services/core/java/com/android/server/timezone/ClockHelper.java
@@ -14,7 +14,12 @@
  * limitations under the License.
  */
 
-package android.app;
+package com.android.server.timezone;
 
-/** @hide */
-parcelable CompatibilityDisplayProperties;
+/**
+ * An easy-to-mock interface for obtaining a monotonically increasing time value in milliseconds.
+ */
+interface ClockHelper {
+
+    long currentTimestamp();
+}
diff --git a/services/core/java/com/android/server/timezone/ConfigHelper.java b/services/core/java/com/android/server/timezone/ConfigHelper.java
new file mode 100644
index 0000000..f9984fa
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/ConfigHelper.java
@@ -0,0 +1,34 @@
+/*
+ * 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.server.timezone;
+
+/**
+ * An easy-to-mock interface around device config for use by {@link PackageTracker}; it is not
+ * possible to test various states with the real one because config is fixed in the system image.
+ */
+interface ConfigHelper {
+
+    boolean isTrackingEnabled();
+
+    String getUpdateAppPackageName();
+
+    String getDataAppPackageName();
+
+    int getCheckTimeAllowedMillis();
+
+    int getFailedCheckRetryCount();
+}
diff --git a/core/java/android/app/CompatibilityDisplayProperties.aidl b/services/core/java/com/android/server/timezone/FileDescriptorHelper.java
similarity index 63%
copy from core/java/android/app/CompatibilityDisplayProperties.aidl
copy to services/core/java/com/android/server/timezone/FileDescriptorHelper.java
index 626a63e..c3b1101 100644
--- a/core/java/android/app/CompatibilityDisplayProperties.aidl
+++ b/services/core/java/com/android/server/timezone/FileDescriptorHelper.java
@@ -14,7 +14,17 @@
  * limitations under the License.
  */
 
-package android.app;
+package com.android.server.timezone;
 
-/** @hide */
-parcelable CompatibilityDisplayProperties;
+import android.os.ParcelFileDescriptor;
+
+import java.io.IOException;
+
+/**
+ * An easy-to-mock interface around use of {@link ParcelFileDescriptor} for use by
+ * {@link RulesManagerService}.
+ */
+interface FileDescriptorHelper {
+
+    byte[] readFully(ParcelFileDescriptor parcelFileDescriptor) throws IOException;
+}
diff --git a/services/core/java/com/android/server/timezone/IntentHelper.java b/services/core/java/com/android/server/timezone/IntentHelper.java
new file mode 100644
index 0000000..0cb9065
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/IntentHelper.java
@@ -0,0 +1,37 @@
+/*
+ * 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.server.timezone;
+
+/**
+ * An easy-to-mock interface around intent sending / receiving for use by {@link PackageTracker};
+ * it is not possible to test various cases with the real one because of the need to simulate
+ * receiving and broadcasting intents.
+ */
+interface IntentHelper {
+
+    void initialize(String updateAppPackageName, String dataAppPackageName, Listener listener);
+
+    void sendTriggerUpdateCheck(CheckToken checkToken);
+
+    void enableReliabilityTriggering();
+
+    void disableReliabilityTriggering();
+
+    interface Listener {
+        void triggerUpdateIfNeeded(boolean packageUpdated);
+    }
+}
diff --git a/services/core/java/com/android/server/timezone/IntentHelperImpl.java b/services/core/java/com/android/server/timezone/IntentHelperImpl.java
new file mode 100644
index 0000000..3ffbb2d
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/IntentHelperImpl.java
@@ -0,0 +1,116 @@
+/*
+ * 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.server.timezone;
+
+import android.app.timezone.RulesUpdaterContract;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.PatternMatcher;
+import android.util.Slog;
+
+import java.util.regex.Pattern;
+
+/**
+ * The bona fide implementation of {@link IntentHelper}.
+ */
+final class IntentHelperImpl implements IntentHelper {
+
+    private final static String TAG = "timezone.IntentHelperImpl";
+
+    private final Context mContext;
+    private String mUpdaterAppPackageName;
+
+    private boolean mReliabilityReceiverEnabled;
+    private Receiver mReliabilityReceiver;
+
+    IntentHelperImpl(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void initialize(
+            String updaterAppPackageName, String dataAppPackageName, Listener listener) {
+        mUpdaterAppPackageName = updaterAppPackageName;
+
+        // Register for events of interest.
+
+        // The intent filter that triggers when package update events happen that indicate there may
+        // be work to do.
+        IntentFilter packageIntentFilter = new IntentFilter();
+        // Either of these mean a downgrade?
+        packageIntentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+        packageIntentFilter.addDataScheme("package");
+        packageIntentFilter.addDataSchemeSpecificPart(
+                updaterAppPackageName, PatternMatcher.PATTERN_LITERAL);
+        packageIntentFilter.addDataSchemeSpecificPart(
+                dataAppPackageName, PatternMatcher.PATTERN_LITERAL);
+        Receiver packageUpdateReceiver = new Receiver(listener, true /* packageUpdated */);
+        mContext.registerReceiver(packageUpdateReceiver, packageIntentFilter);
+
+        // TODO(nfuller): Add more exotic intents as needed. e.g.
+        // packageIntentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+        // Also, disabled...?
+        mReliabilityReceiver = new Receiver(listener, false /* packageUpdated */);
+    }
+
+    /** Sends an intent to trigger an update check. */
+    @Override
+    public void sendTriggerUpdateCheck(CheckToken checkToken) {
+        RulesUpdaterContract.sendBroadcast(
+                mContext, mUpdaterAppPackageName, checkToken.toByteArray());
+    }
+
+    @Override
+    public synchronized void enableReliabilityTriggering() {
+        if (!mReliabilityReceiverEnabled) {
+            // The intent filter that exists to make updates reliable in the event of failures /
+            // reboots.
+            IntentFilter reliabilityIntentFilter = new IntentFilter();
+            reliabilityIntentFilter.addAction(Intent.ACTION_IDLE_MAINTENANCE_START);
+            mContext.registerReceiver(mReliabilityReceiver, reliabilityIntentFilter);
+            mReliabilityReceiverEnabled = true;
+        }
+    }
+
+    @Override
+    public synchronized void disableReliabilityTriggering() {
+        if (mReliabilityReceiverEnabled) {
+            mContext.unregisterReceiver(mReliabilityReceiver);
+            mReliabilityReceiverEnabled = false;
+        }
+    }
+
+    private static class Receiver extends BroadcastReceiver {
+        private final Listener mListener;
+        private final boolean mPackageUpdated;
+
+        private Receiver(Listener listener, boolean packageUpdated) {
+            mListener = listener;
+            mPackageUpdated = packageUpdated;
+        }
+
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            Slog.d(TAG, "Received intent: " + intent.toString());
+            mListener.triggerUpdateIfNeeded(mPackageUpdated);
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/timezone/PackageManagerHelper.java b/services/core/java/com/android/server/timezone/PackageManagerHelper.java
new file mode 100644
index 0000000..804941a
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/PackageManagerHelper.java
@@ -0,0 +1,41 @@
+/*
+ * 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.server.timezone;
+
+import android.content.Intent;
+import android.content.pm.PackageManager;
+
+/**
+ * An easy-to-mock facade around PackageManager for use by {@link PackageTracker}; it is not
+ * possible to test various cases with the real one because of the need to simulate package versions
+ * and manifest configurations.
+ */
+interface PackageManagerHelper {
+
+    int getInstalledPackageVersion(String packageName)
+            throws PackageManager.NameNotFoundException;
+
+    boolean isPrivilegedApp(String packageName) throws PackageManager.NameNotFoundException;
+
+    boolean usesPermission(String packageName, String requiredPermissionName)
+                    throws PackageManager.NameNotFoundException;
+
+    boolean contentProviderRegistered(String authority, String requiredPackageName);
+
+    boolean receiverRegistered(Intent intent, String requiredPermissionName)
+                            throws PackageManager.NameNotFoundException;
+}
diff --git a/services/core/java/com/android/server/timezone/PackageStatus.java b/services/core/java/com/android/server/timezone/PackageStatus.java
new file mode 100644
index 0000000..6379096
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/PackageStatus.java
@@ -0,0 +1,89 @@
+/*
+ * 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.server.timezone;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Information about the status of the time zone update / data packages that are persisted by the
+ * Android system.
+ */
+final class PackageStatus {
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ CHECK_STARTED, CHECK_COMPLETED_SUCCESS, CHECK_COMPLETED_FAILURE })
+    @interface CheckStatus {}
+
+    /** A time zone update check has been started but not yet completed. */
+    static final int CHECK_STARTED = 1;
+    /** A time zone update check has been completed and succeeded. */
+    static final int CHECK_COMPLETED_SUCCESS = 2;
+    /** A time zone update check has been completed and failed. */
+    static final int CHECK_COMPLETED_FAILURE = 3;
+
+    @CheckStatus
+    final int mCheckStatus;
+
+    // Non-null
+    final PackageVersions mVersions;
+
+    PackageStatus(@CheckStatus int checkStatus, PackageVersions versions) {
+        this.mCheckStatus = checkStatus;
+        if (checkStatus < 1 || checkStatus > 3) {
+            throw new IllegalArgumentException("Unknown checkStatus " + checkStatus);
+        }
+        if (versions == null) {
+            throw new NullPointerException("versions == null");
+        }
+        this.mVersions = versions;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        PackageStatus that = (PackageStatus) o;
+
+        if (mCheckStatus != that.mCheckStatus) {
+            return false;
+        }
+        return mVersions.equals(that.mVersions);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mCheckStatus;
+        result = 31 * result + mVersions.hashCode();
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "PackageStatus{" +
+                "mCheckStatus=" + mCheckStatus +
+                ", mVersions=" + mVersions +
+                '}';
+    }
+}
diff --git a/services/core/java/com/android/server/timezone/PackageStatusStorage.java b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
new file mode 100644
index 0000000..31f0e31
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/PackageStatusStorage.java
@@ -0,0 +1,336 @@
+/*
+ * 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.server.timezone;
+
+import android.content.ContentValues;
+import android.content.Context;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Slog;
+
+import java.io.File;
+
+import static com.android.server.timezone.PackageStatus.CHECK_COMPLETED_FAILURE;
+import static com.android.server.timezone.PackageStatus.CHECK_COMPLETED_SUCCESS;
+import static com.android.server.timezone.PackageStatus.CHECK_STARTED;
+
+/**
+ * Storage logic for accessing/mutating the Android system's persistent state related to time zone
+ * update checking. There is expected to be a single instance and all methods synchronized on
+ * {@code this} for thread safety.
+ */
+final class PackageStatusStorage {
+
+    private static final String TAG = "timezone.PackageStatusStorage";
+
+    private static final String DATABASE_NAME = "timezonepackagestatus.db";
+    private static final int DATABASE_VERSION = 1;
+
+    /** The table name. It will have a single row with _id == {@link #SINGLETON_ID} */
+    private static final String TABLE = "status";
+    private static final String COLUMN_ID = "_id";
+
+    /**
+     * Column that stores a monotonically increasing lock ID, used to detect concurrent update
+     * issues without on-line locks. Incremented on every write.
+     */
+    private static final String COLUMN_OPTIMISTIC_LOCK_ID = "optimistic_lock_id";
+
+    /**
+     * Column that stores the current "check status" of the time zone update application packages.
+     */
+    private static final String COLUMN_CHECK_STATUS = "check_status";
+
+    /**
+     * Column that stores the version of the time zone rules update application being checked / last
+     * checked.
+     */
+    private static final String COLUMN_UPDATE_APP_VERSION = "update_app_package_version";
+
+    /**
+     * Column that stores the version of the time zone rules data application being checked / last
+     * checked.
+     */
+    private static final String COLUMN_DATA_APP_VERSION = "data_app_package_version";
+
+    /**
+     * The ID of the one row.
+     */
+    private static final int SINGLETON_ID = 1;
+
+    private static final int UNKNOWN_PACKAGE_VERSION = -1;
+
+    private final DatabaseHelper mDatabaseHelper;
+
+    PackageStatusStorage(Context context) {
+        mDatabaseHelper = new DatabaseHelper(context);
+    }
+
+    void deleteDatabaseForTests() {
+        SQLiteDatabase.deleteDatabase(mDatabaseHelper.getDatabaseFile());
+    }
+
+    /**
+     * Obtain the current check status of the application packages. Returns {@code null} the first
+     * time it is called, or after {@link #resetCheckState()}.
+     */
+    PackageStatus getPackageStatus() {
+        synchronized (this) {
+            try {
+                return getPackageStatusInternal();
+            } catch (IllegalArgumentException e) {
+                // This means that data exists in the table but it was bad.
+                Slog.e(TAG, "Package status invalid, resetting and retrying", e);
+
+                // Reset the storage so it is in a good state again.
+                mDatabaseHelper.recoverFromBadData();
+                return getPackageStatusInternal();
+            }
+        }
+    }
+
+    private PackageStatus getPackageStatusInternal() {
+        String[] columns = {
+                COLUMN_CHECK_STATUS, COLUMN_UPDATE_APP_VERSION, COLUMN_DATA_APP_VERSION
+        };
+        Cursor cursor = mDatabaseHelper.getReadableDatabase()
+                .query(TABLE, columns, COLUMN_ID + " = ?",
+                        new String[] { Integer.toString(SINGLETON_ID) },
+                        null /* groupBy */, null /* having */, null /* orderBy */);
+        if (cursor.getCount() != 1) {
+            Slog.e(TAG, "Unable to find package status from package status row. Rows returned: "
+                    + cursor.getCount());
+            return null;
+        }
+        cursor.moveToFirst();
+
+        // Determine check status.
+        if (cursor.isNull(0)) {
+            // This is normal the first time getPackageStatus() is called, or after
+            // resetCheckState().
+            return null;
+        }
+        int checkStatus = cursor.getInt(0);
+
+        // Determine package version.
+        if (cursor.isNull(1) || cursor.isNull(2)) {
+            Slog.e(TAG, "Package version information unexpectedly null");
+            return null;
+        }
+        PackageVersions packageVersions = new PackageVersions(cursor.getInt(1), cursor.getInt(2));
+
+        return new PackageStatus(checkStatus, packageVersions);
+    }
+
+    /**
+     * Generate a new {@link CheckToken} that can be passed to the time zone rules update
+     * application.
+     */
+    CheckToken generateCheckToken(PackageVersions currentInstalledVersions) {
+        if (currentInstalledVersions == null) {
+            throw new NullPointerException("currentInstalledVersions == null");
+        }
+
+        synchronized (this) {
+            Integer optimisticLockId = getCurrentOptimisticLockId();
+            if (optimisticLockId == null) {
+                Slog.w(TAG, "Unable to find optimistic lock ID from package status row");
+
+                // Recover.
+                optimisticLockId = mDatabaseHelper.recoverFromBadData();
+            }
+
+            int newOptimisticLockId = optimisticLockId + 1;
+            boolean statusRowUpdated = writeStatusRow(
+                    optimisticLockId, newOptimisticLockId, CHECK_STARTED, currentInstalledVersions);
+            if (!statusRowUpdated) {
+                Slog.e(TAG, "Unable to update status to CHECK_STARTED in package status row."
+                        + " synchronization failure?");
+                return null;
+            }
+            return new CheckToken(newOptimisticLockId, currentInstalledVersions);
+        }
+    }
+
+    /**
+     * Reset the current device state to "unknown".
+     */
+    void resetCheckState() {
+        synchronized(this) {
+            Integer optimisticLockId = getCurrentOptimisticLockId();
+            if (optimisticLockId == null) {
+                Slog.w(TAG, "resetCheckState: Unable to find optimistic lock ID from package"
+                        + " status row");
+                // Attempt to recover the storage state.
+                optimisticLockId = mDatabaseHelper.recoverFromBadData();
+            }
+
+            int newOptimisticLockId = optimisticLockId + 1;
+            if (!writeStatusRow(optimisticLockId, newOptimisticLockId,
+                    null /* status */, null /* packageVersions */)) {
+                Slog.e(TAG, "resetCheckState: Unable to reset package status row,"
+                        + " newOptimisticLockId=" + newOptimisticLockId);
+            }
+        }
+    }
+
+    /**
+     * Update the current device state if possible. Returns true if the update was successful.
+     * {@code false} indicates the storage has been changed since the {@link CheckToken} was
+     * generated and the update was discarded.
+     */
+    boolean markChecked(CheckToken checkToken, boolean succeeded) {
+        synchronized (this) {
+            int optimisticLockId = checkToken.mOptimisticLockId;
+            int newOptimisticLockId = optimisticLockId + 1;
+            int status = succeeded ? CHECK_COMPLETED_SUCCESS : CHECK_COMPLETED_FAILURE;
+            return writeStatusRow(optimisticLockId, newOptimisticLockId,
+                    status, checkToken.mPackageVersions);
+        }
+    }
+
+    // Caller should be synchronized(this)
+    private Integer getCurrentOptimisticLockId() {
+        final String[] columns = { COLUMN_OPTIMISTIC_LOCK_ID };
+        final String querySelection = COLUMN_ID + " = ?";
+        final String[] querySelectionArgs = { Integer.toString(SINGLETON_ID) };
+
+        SQLiteDatabase database = mDatabaseHelper.getReadableDatabase();
+        try (Cursor cursor = database.query(TABLE, columns, querySelection, querySelectionArgs,
+                null /* groupBy */, null /* having */, null /* orderBy */)) {
+            if (cursor.getCount() != 1) {
+                Slog.w(TAG, cursor.getCount() + " rows returned, expected exactly one.");
+                return null;
+            }
+            cursor.moveToFirst();
+            return cursor.getInt(0);
+        }
+    }
+
+    // Caller should be synchronized(this)
+    private boolean writeStatusRow(int optimisticLockId, int newOptimisticLockId, Integer status,
+            PackageVersions packageVersions) {
+        if ((status == null) != (packageVersions == null)) {
+            throw new IllegalArgumentException(
+                    "Provide both status and packageVersions, or neither.");
+        }
+
+        SQLiteDatabase database = mDatabaseHelper.getWritableDatabase();
+        ContentValues values = new ContentValues();
+        values.put(COLUMN_OPTIMISTIC_LOCK_ID, newOptimisticLockId);
+        if (status == null) {
+            values.putNull(COLUMN_CHECK_STATUS);
+            values.put(COLUMN_UPDATE_APP_VERSION, UNKNOWN_PACKAGE_VERSION);
+            values.put(COLUMN_DATA_APP_VERSION, UNKNOWN_PACKAGE_VERSION);
+        } else {
+            values.put(COLUMN_CHECK_STATUS, status);
+            values.put(COLUMN_UPDATE_APP_VERSION, packageVersions.mUpdateAppVersion);
+            values.put(COLUMN_DATA_APP_VERSION, packageVersions.mDataAppVersion);
+        }
+
+        String updateSelection = COLUMN_ID + " = ? AND " + COLUMN_OPTIMISTIC_LOCK_ID + " = ?";
+        String[] updateSelectionArgs = {
+                Integer.toString(SINGLETON_ID), Integer.toString(optimisticLockId)
+        };
+        int count = database.update(TABLE, values, updateSelection, updateSelectionArgs);
+        if (count > 1) {
+            // This has to be because of corruption: there should only ever be one row.
+            Slog.w(TAG, "writeStatusRow: " + count + " rows updated, expected exactly one.");
+            // Reset the table.
+            mDatabaseHelper.recoverFromBadData();
+        }
+
+        // 1 is the success case. 0 rows updated means the row is missing or the optimistic lock ID
+        // was not as expected, this could be because of corruption but is most likely due to an
+        // optimistic lock failure. Callers can decide on a case-by-case basis.
+        return count == 1;
+    }
+
+    /** Only used during tests to force an empty table. */
+    void deleteRowForTests() {
+        mDatabaseHelper.getWritableDatabase().delete(TABLE, null, null);
+    }
+
+    /** Only used during tests to force a known table state. */
+    public void forceCheckStateForTests(int checkStatus, PackageVersions packageVersions) {
+        int optimisticLockId = getCurrentOptimisticLockId();
+        writeStatusRow(optimisticLockId, optimisticLockId, checkStatus, packageVersions);
+    }
+
+    static class DatabaseHelper extends SQLiteOpenHelper {
+
+        private final Context mContext;
+
+        public DatabaseHelper(Context context) {
+            super(context, DATABASE_NAME, null, DATABASE_VERSION);
+            mContext = context;
+        }
+
+        @Override
+        public void onCreate(SQLiteDatabase db) {
+            db.execSQL("CREATE TABLE " + TABLE + " (" +
+                    "_id INTEGER PRIMARY KEY," +
+                    COLUMN_OPTIMISTIC_LOCK_ID + " INTEGER NOT NULL," +
+                    COLUMN_CHECK_STATUS + " INTEGER," +
+                    COLUMN_UPDATE_APP_VERSION + " INTEGER NOT NULL," +
+                    COLUMN_DATA_APP_VERSION + " INTEGER NOT NULL" +
+                    ");");
+            insertInitialRowState(db);
+        }
+
+        @Override
+        public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
+            // no-op: nothing to upgrade
+        }
+
+        /** Recover the initial data row state, returning the new current optimistic lock ID */
+        int recoverFromBadData() {
+            // Delete the table content.
+            SQLiteDatabase writableDatabase = getWritableDatabase();
+            writableDatabase.delete(TABLE, null /* whereClause */, null /* whereArgs */);
+
+            // Insert the initial content.
+            return insertInitialRowState(writableDatabase);
+        }
+
+        /** Insert the initial data row, returning the optimistic lock ID */
+        private static int insertInitialRowState(SQLiteDatabase db) {
+            // Doesn't matter what it is, but we avoid the obvious starting value each time the row
+            // is reset to ensure that old tokens are unlikely to work.
+           final int initialOptimisticLockId = (int) System.currentTimeMillis();
+
+            // Insert the one row.
+            ContentValues values = new ContentValues();
+            values.put(COLUMN_ID, SINGLETON_ID);
+            values.put(COLUMN_OPTIMISTIC_LOCK_ID, initialOptimisticLockId);
+            values.putNull(COLUMN_CHECK_STATUS);
+            values.put(COLUMN_UPDATE_APP_VERSION, UNKNOWN_PACKAGE_VERSION);
+            values.put(COLUMN_DATA_APP_VERSION, UNKNOWN_PACKAGE_VERSION);
+            long id = db.insert(TABLE, null, values);
+            if (id == -1) {
+                Slog.w(TAG, "insertInitialRow: could not insert initial row, id=" + id);
+                return -1;
+            }
+            return initialOptimisticLockId;
+        }
+
+        File getDatabaseFile() {
+            return mContext.getDatabasePath(DATABASE_NAME);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/timezone/PackageTracker.java b/services/core/java/com/android/server/timezone/PackageTracker.java
new file mode 100644
index 0000000..8abf7df
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/PackageTracker.java
@@ -0,0 +1,504 @@
+/*
+ * 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.server.timezone;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import android.app.timezone.RulesUpdaterContract;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.provider.TimeZoneRulesDataContract;
+import android.util.Slog;
+
+/**
+ * Monitors the installed applications associated with time zone updates. If the app packages are
+ * updated it indicates there <em>might</em> be a time zone rules update to apply so a targeted
+ * broadcast intent is used to trigger the time zone updater app.
+ *
+ * <p>The "update triggering" behavior of this component can be disabled via device configuration.
+ *
+ * <p>The package tracker listens for package updates of the time zone "updater app" and "data app".
+ * It also listens for "reliability" triggers. Reliability triggers are there to ensure that the
+ * package tracker handles failures reliably and are "idle maintenance" events or something similar.
+ * Reliability triggers can cause a time zone update check to take place if the current state is
+ * unclear. For example, it can be unclear after boot or after a failure. If there are repeated
+ * failures reliability updates are halted until the next boot.
+ *
+ * <p>This component keeps persistent track of the most recent app packages checked to avoid
+ * unnecessary expense from broadcasting intents (which will cause other app processes to spawn).
+ * The current status is also stored to detect whether the most recently-generated check is
+ * complete successfully. For example, if the device was interrupted while doing a check and never
+ * acknowledged a check then a check will be retried the next time a "reliability trigger" event
+ * happens.
+ */
+// Also made non-final so it can be mocked.
+@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+public class PackageTracker implements IntentHelper.Listener {
+    private static final String TAG = "timezone.PackageTracker";
+
+    private final PackageManagerHelper mPackageManagerHelper;
+    private final IntentHelper mIntentHelper;
+    private final ConfigHelper mConfigHelper;
+    private final PackageStatusStorage mPackageStatusStorage;
+    private final ClockHelper mClockHelper;
+
+    // False if tracking is disabled.
+    private boolean mTrackingEnabled;
+
+    // These fields may be null if package tracking is disabled.
+    private String mUpdateAppPackageName;
+    private String mDataAppPackageName;
+
+    // The time a triggered check is allowed to take before it is considered overdue.
+    private int mCheckTimeAllowedMillis;
+    // The number of failed checks in a row before reliability checks should stop happening.
+    private long mFailedCheckRetryCount;
+
+    // Reliability check state: If a check was triggered but not acknowledged within
+    // mCheckTimeAllowedMillis then another one can be triggered.
+    private Long mLastTriggerTimestamp = null;
+
+    // Reliability check state: Whether any checks have been triggered at all.
+    private boolean mCheckTriggered;
+
+    // Reliability check state: A count of how many failures have occurred consecutively.
+    private int mCheckFailureCount;
+
+    /** Creates the {@link PackageTracker} for normal use. */
+    static PackageTracker create(Context context) {
+        PackageTrackerHelperImpl helperImpl = new PackageTrackerHelperImpl(context);
+        return new PackageTracker(
+                helperImpl /* clock */,
+                helperImpl /* configHelper */,
+                helperImpl /* packageManagerHelper */,
+                new PackageStatusStorage(context),
+                new IntentHelperImpl(context));
+    }
+
+    // A constructor that can be used by tests to supply mocked / faked dependencies.
+    PackageTracker(ClockHelper clockHelper, ConfigHelper configHelper,
+            PackageManagerHelper packageManagerHelper, PackageStatusStorage packageStatusStorage,
+            IntentHelper intentHelper) {
+        mClockHelper = clockHelper;
+        mConfigHelper = configHelper;
+        mPackageManagerHelper = packageManagerHelper;
+        mPackageStatusStorage = packageStatusStorage;
+        mIntentHelper = intentHelper;
+    }
+
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    protected synchronized void start() {
+        mTrackingEnabled = mConfigHelper.isTrackingEnabled();
+        if (!mTrackingEnabled) {
+            Slog.i(TAG, "Time zone updater / data package tracking explicitly disabled.");
+            return;
+        }
+
+        mUpdateAppPackageName = mConfigHelper.getUpdateAppPackageName();
+        mDataAppPackageName = mConfigHelper.getDataAppPackageName();
+        mCheckTimeAllowedMillis = mConfigHelper.getCheckTimeAllowedMillis();
+        mFailedCheckRetryCount = mConfigHelper.getFailedCheckRetryCount();
+
+        // Validate the device configuration including the application packages.
+        // The manifest entries in the apps themselves are not validated until use as they can
+        // change and we don't want to prevent the system server starting due to a bad application.
+        throwIfDeviceSettingsOrAppsAreBad();
+
+        // Explicitly start in a reliability state where reliability triggering will do something.
+        mCheckTriggered = false;
+        mCheckFailureCount = 0;
+
+        // Initialize the intent helper.
+        mIntentHelper.initialize(mUpdateAppPackageName, mDataAppPackageName, this);
+
+        // Enable the reliability triggering so we will have at least one reliability trigger if
+        // a package isn't updated.
+        mIntentHelper.enableReliabilityTriggering();
+
+        Slog.i(TAG, "Time zone updater / data package tracking enabled");
+    }
+
+    /**
+     * Performs checks that confirm the system image has correctly configured package
+     * tracking configuration. Only called if package tracking is enabled. Throws an exception if
+     * the device is configured badly which will prevent the device booting.
+     */
+    private void throwIfDeviceSettingsOrAppsAreBad() {
+        // None of the checks below can be based on application manifest settings, otherwise a bad
+        // update could leave the device in an unbootable state. See validateDataAppManifest() and
+        // validateUpdaterAppManifest() for softer errors.
+
+        throwRuntimeExceptionIfNullOrEmpty(
+                mUpdateAppPackageName, "Update app package name missing.");
+        throwRuntimeExceptionIfNullOrEmpty(mDataAppPackageName, "Data app package name missing.");
+        if (mFailedCheckRetryCount < 1) {
+            throw logAndThrowRuntimeException("mFailedRetryCount=" + mFailedCheckRetryCount, null);
+        }
+        if (mCheckTimeAllowedMillis < 1000) {
+            throw logAndThrowRuntimeException(
+                    "mCheckTimeAllowedMillis=" + mCheckTimeAllowedMillis, null);
+        }
+
+        // Validate the updater application package.
+        // TODO(nfuller) Uncomment or remove the code below. Currently an app stops being a priv-app
+        // after it is replaced by one in data so this check fails. http://b/35995024
+        // try {
+        //     if (!mPackageManagerHelper.isPrivilegedApp(mUpdateAppPackageName)) {
+        //         throw failWithException(
+        //                 "Update app " + mUpdateAppPackageName + " must be a priv-app.", null);
+        //     }
+        // } catch (PackageManager.NameNotFoundException e) {
+        //     throw failWithException("Could not determine update app package details for "
+        //             + mUpdateAppPackageName, e);
+        // }
+        // TODO(nfuller) Consider permission checks. While an updated system app retains permissions
+        // obtained by the system version it's not clear how to check them.
+        Slog.d(TAG, "Update app " + mUpdateAppPackageName + " is valid.");
+
+        // Validate the data application package.
+        // TODO(nfuller) Uncomment or remove the code below. Currently an app stops being a priv-app
+        // after it is replaced by one in data. http://b/35995024
+        // try {
+        //     if (!mPackageManagerHelper.isPrivilegedApp(mDataAppPackageName)) {
+        //         throw failWithException(
+        //                 "Data app " + mDataAppPackageName + " must be a priv-app.", null);
+        //     }
+        // } catch (PackageManager.NameNotFoundException e) {
+        //     throw failWithException("Could not determine data app package details for "
+        //             + mDataAppPackageName, e);
+        // }
+        // TODO(nfuller) Consider permission checks. While an updated system app retains permissions
+        // obtained by the system version it's not clear how to check them.
+        Slog.d(TAG, "Data app " + mDataAppPackageName + " is valid.");
+    }
+
+    /**
+     * Inspects the current in-memory state, installed packages and storage state to determine if an
+     * update check is needed and then trigger if it is.
+     *
+     * @param packageChanged true if this method was called because a known packaged definitely
+     *     changed, false if the cause is a reliability trigger
+     */
+    @Override
+    public synchronized void triggerUpdateIfNeeded(boolean packageChanged) {
+        if (!mTrackingEnabled) {
+            throw new IllegalStateException("Unexpected call. Tracking is disabled.");
+        }
+
+        // Validate the applications' current manifest entries: make sure they are configured as
+        // they should be. These are not fatal and just means that no update is triggered: we don't
+        // want to take down the system server if an OEM or Google have pushed a bad update to
+        // an application.
+        boolean updaterAppManifestValid = validateUpdaterAppManifest();
+        boolean dataAppManifestValid = validateDataAppManifest();
+        if (!updaterAppManifestValid || !dataAppManifestValid) {
+            Slog.e(TAG, "No update triggered due to invalid application manifest entries."
+                    + " updaterApp=" + updaterAppManifestValid
+                    + ", dataApp=" + dataAppManifestValid);
+
+            // There's no point in doing reliability checks if the current packages are bad.
+            mIntentHelper.disableReliabilityTriggering();
+            return;
+        }
+
+        if (!packageChanged) {
+            // This call was made because the device is doing a "reliability" check.
+            // 4 possible cases:
+            // 1) No check has previously triggered since restart. We want to trigger in this case.
+            // 2) A check has previously triggered and it is in progress. We want to trigger if
+            //    the response is overdue.
+            // 3) A check has previously triggered and it failed. We want to trigger, but only if
+            //    we're not in a persistent failure state.
+            // 4) A check has previously triggered and it succeeded.
+            //    We don't want to trigger, and want to stop future triggers.
+
+            if (!mCheckTriggered) {
+                // Case 1.
+                Slog.d(TAG, "triggerUpdateIfNeeded: First reliability trigger.");
+            } else if (isCheckInProgress()) {
+                // Case 2.
+                if (!isCheckResponseOverdue()) {
+                    // A check is in progress but hasn't been given time to succeed.
+                    Slog.d(TAG,
+                            "triggerUpdateIfNeeded: checkComplete call is not yet overdue."
+                                    + " Not triggering.");
+                    // Not doing any work, but also not disabling future reliability triggers.
+                    return;
+                }
+            } else if (mCheckFailureCount > mFailedCheckRetryCount) {
+                // Case 3. If the system is in some kind of persistent failure state we don't want
+                // to keep checking, so just stop.
+                Slog.i(TAG, "triggerUpdateIfNeeded: number of allowed consecutive check failures"
+                        + " exceeded. Stopping reliability triggers until next reboot or package"
+                        + " update.");
+                mIntentHelper.disableReliabilityTriggering();
+                return;
+            } else if (mCheckFailureCount == 0) {
+                // Case 4.
+                Slog.i(TAG, "triggerUpdateIfNeeded: No reliability check required. Last check was"
+                        + " successful.");
+                mIntentHelper.disableReliabilityTriggering();
+                return;
+            }
+        }
+
+        // Read the currently installed data / updater package versions.
+        PackageVersions currentInstalledVersions = lookupInstalledPackageVersions();
+        if (currentInstalledVersions == null) {
+            // This should not happen if the device is configured in a valid way.
+            Slog.e(TAG, "triggerUpdateIfNeeded: currentInstalledVersions was null");
+            mIntentHelper.disableReliabilityTriggering();
+            return;
+        }
+
+        // Establish the current state using package manager and stored state. Determine if we have
+        // already successfully checked the installed versions.
+        PackageStatus packageStatus = mPackageStatusStorage.getPackageStatus();
+        if (packageStatus == null) {
+            // This can imply corrupt, uninitialized storage state (e.g. first check ever on a
+            // device) or after some kind of reset.
+            Slog.i(TAG, "triggerUpdateIfNeeded: No package status data found. Data check needed.");
+        } else if (!packageStatus.mVersions.equals(currentInstalledVersions)) {
+            // The stored package version information differs from the installed version.
+            // Trigger the check in all cases.
+            Slog.i(TAG, "triggerUpdateIfNeeded: Stored package versions="
+                    + packageStatus.mVersions + ", do not match current package versions="
+                    + currentInstalledVersions + ". Triggering check.");
+        } else {
+            Slog.i(TAG, "triggerUpdateIfNeeded: Stored package versions match currently"
+                    + " installed versions, currentInstalledVersions=" + currentInstalledVersions
+                    + ", packageStatus.mCheckStatus=" + packageStatus.mCheckStatus);
+            if (packageStatus.mCheckStatus == PackageStatus.CHECK_COMPLETED_SUCCESS) {
+                // The last check succeeded and nothing has changed. Do nothing and disable
+                // reliability checks.
+                Slog.i(TAG, "triggerUpdateIfNeeded: Prior check succeeded. No need to trigger.");
+                mIntentHelper.disableReliabilityTriggering();
+                return;
+            }
+        }
+
+        // Generate a token to send to the updater app.
+        CheckToken checkToken =
+                mPackageStatusStorage.generateCheckToken(currentInstalledVersions);
+        if (checkToken == null) {
+            Slog.w(TAG, "triggerUpdateIfNeeded: Unable to generate check token."
+                    + " Not sending check request.");
+            return;
+        }
+
+        // Trigger the update check.
+        mIntentHelper.sendTriggerUpdateCheck(checkToken);
+        mCheckTriggered = true;
+
+        // Update the reliability check state in case the update fails.
+        setCheckInProgress();
+
+        // Enable reliability triggering in case the check doesn't succeed and there is no
+        // response at all. Enabling reliability triggering is idempotent.
+        mIntentHelper.enableReliabilityTriggering();
+    }
+
+    /**
+     * Used to record the result of a check. Can be called even if active package tracking is
+     * disabled.
+     */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    protected synchronized void recordCheckResult(CheckToken checkToken, boolean success) {
+        Slog.i(TAG, "recordOperationResult: checkToken=" + checkToken + " success=" + success);
+
+        // If package tracking is disabled it means no record-keeping is required. However, we do
+        // want to clear out any stored state to make it clear that the current state is unknown and
+        // should tracking become enabled again (perhaps through an OTA) we'd need to perform an
+        // update check.
+        if (!mTrackingEnabled) {
+            // This means an updater has spontaneously modified time zone data without having been
+            // triggered. This can happen if the OEM is handling their own updates, but we don't
+            // need to do any tracking in this case.
+
+            if (checkToken == null) {
+                // This is the expected case if tracking is disabled but an OEM is handling time
+                // zone installs using their own mechanism.
+                Slog.d(TAG, "recordCheckResult: Tracking is disabled and no token has been"
+                        + " provided. Resetting tracking state.");
+            } else {
+                // This is unexpected. If tracking is disabled then no check token should have been
+                // generated by the package tracker. An updater should never create its own token.
+                // This could be a bug in the updater.
+                Slog.w(TAG, "recordCheckResult: Tracking is disabled and a token " + checkToken
+                        + " has been unexpectedly provided. Resetting tracking state.");
+            }
+            mPackageStatusStorage.resetCheckState();
+            return;
+        }
+
+        if (checkToken == null) {
+            /*
+             * If the checkToken is null it suggests an install / uninstall / acknowledgement has
+             * occurred without a prior trigger (or the client didn't return the token it was given
+             * for some reason, perhaps a bug).
+             *
+             * This shouldn't happen under normal circumstances:
+             *
+             * If package tracking is enabled, we assume it is the package tracker responsible for
+             * triggering updates and a token should have been produced and returned.
+             *
+             * If the OEM is handling time zone updates case package tracking should be disabled.
+             *
+             * This could happen in tests. The device should recover back to a known state by
+             * itself rather than be left in an invalid state.
+             *
+             * We treat this as putting the device into an unknown state and make sure that
+             * reliability triggering is enabled so we should recover.
+             */
+            Slog.i(TAG, "recordCheckResult: Unexpectedly missing checkToken, resetting"
+                    + " storage state.");
+            mPackageStatusStorage.resetCheckState();
+
+            // Enable reliability triggering and reset the failure count so we know that the
+            // next reliability trigger will do something.
+            mIntentHelper.enableReliabilityTriggering();
+            mCheckFailureCount = 0;
+        } else {
+            // This is the expected case when tracking is enabled: a check was triggered and it has
+            // completed.
+            boolean recordedCheckCompleteSuccessfully =
+                    mPackageStatusStorage.markChecked(checkToken, success);
+            if (recordedCheckCompleteSuccessfully) {
+                // If we have recorded the result (whatever it was) we know there is no check in
+                // progress.
+                setCheckComplete();
+
+                if (success) {
+                    // Since the check was successful, no more reliability checks are required until
+                    // there is a package change.
+                    mIntentHelper.disableReliabilityTriggering();
+                    mCheckFailureCount = 0;
+                } else {
+                    // Enable reliability triggering to potentially check again in future.
+                    mIntentHelper.enableReliabilityTriggering();
+                    mCheckFailureCount++;
+                }
+            } else {
+                // The failure to record the check means an optimistic lock failure and suggests
+                // that another check was triggered after the token was generated.
+                Slog.i(TAG, "recordCheckResult: could not update token=" + checkToken
+                        + " with success=" + success + ". Optimistic lock failure");
+
+                // Enable reliability triggering to potentially try again in future.
+                mIntentHelper.enableReliabilityTriggering();
+                mCheckFailureCount++;
+            }
+        }
+    }
+
+    /** Access to consecutive failure counts for use in tests. */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+    protected int getCheckFailureCountForTests() {
+        return mCheckFailureCount;
+    }
+
+    private void setCheckInProgress() {
+        mLastTriggerTimestamp = mClockHelper.currentTimestamp();
+    }
+
+    private void setCheckComplete() {
+        mLastTriggerTimestamp = null;
+    }
+
+    private boolean isCheckInProgress() {
+        return mLastTriggerTimestamp != null;
+    }
+
+    private boolean isCheckResponseOverdue() {
+        if (mLastTriggerTimestamp == null) {
+            return false;
+        }
+        // Risk of overflow, but highly unlikely given the implementation and not problematic.
+        return mClockHelper.currentTimestamp() > mLastTriggerTimestamp + mCheckTimeAllowedMillis;
+    }
+
+    private PackageVersions lookupInstalledPackageVersions() {
+        int updatePackageVersion;
+        int dataPackageVersion;
+        try {
+            updatePackageVersion =
+                    mPackageManagerHelper.getInstalledPackageVersion(mUpdateAppPackageName);
+            dataPackageVersion =
+                    mPackageManagerHelper.getInstalledPackageVersion(mDataAppPackageName);
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.w(TAG, "lookupInstalledPackageVersions: Unable to resolve installed package"
+                    + " versions", e);
+            return null;
+        }
+        return new PackageVersions(updatePackageVersion, dataPackageVersion);
+    }
+
+    private boolean validateDataAppManifest() {
+        // We only want to talk to a provider that exposed by the known data app package
+        // so we look up the providers exposed by that app and check the well-known authority is
+        // there. This prevents the case where *even if* the data app doesn't expose the provider
+        // required, another app cannot expose one to replace it.
+        if (!mPackageManagerHelper.contentProviderRegistered(
+                TimeZoneRulesDataContract.AUTHORITY, mDataAppPackageName)) {
+            // Error! Found the package but it didn't expose the correct provider.
+            Slog.w(TAG, "validateDataAppManifest: Data app " + mDataAppPackageName
+                    + " does not expose the required provider with authority="
+                    + TimeZoneRulesDataContract.AUTHORITY);
+            return false;
+        }
+        // TODO(nfuller) Add any permissions checks needed.
+        return true;
+    }
+
+    private boolean validateUpdaterAppManifest() {
+        try {
+            // The updater app is expected to have the UPDATE_TIME_ZONE_RULES permission.
+            // The updater app is expected to have a receiver for the intent we are going to trigger
+            // and require the TRIGGER_TIME_ZONE_RULES_CHECK.
+            if (!mPackageManagerHelper.usesPermission(
+                    mUpdateAppPackageName,
+                    RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION)) {
+                Slog.w(TAG, "validateUpdaterAppManifest: Updater app " + mDataAppPackageName
+                        + " does not use permission="
+                        + RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION);
+                return false;
+            }
+            if (!mPackageManagerHelper.receiverRegistered(
+                    RulesUpdaterContract.createUpdaterIntent(mUpdateAppPackageName),
+                    RulesUpdaterContract.TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION)) {
+                return false;
+            }
+
+            return true;
+        } catch (PackageManager.NameNotFoundException e) {
+            Slog.w(TAG, "validateUpdaterAppManifest: Updater app " + mDataAppPackageName
+                    + " does not expose the required broadcast receiver.", e);
+            return false;
+        }
+    }
+
+    private static void throwRuntimeExceptionIfNullOrEmpty(String value, String message) {
+        if (value == null || value.trim().isEmpty()) {
+            throw logAndThrowRuntimeException(message, null);
+        }
+    }
+
+    private static RuntimeException logAndThrowRuntimeException(String message, Throwable cause) {
+        Slog.wtf(TAG, message, cause);
+        throw new RuntimeException(message, cause);
+    }
+}
diff --git a/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
new file mode 100644
index 0000000..2e0c21b
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/PackageTrackerHelperImpl.java
@@ -0,0 +1,154 @@
+/*
+ * 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.server.timezone;
+
+import com.android.internal.R;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.SystemClock;
+import android.util.Slog;
+
+import java.util.List;
+
+/**
+ * A single class that implements multiple helper interfaces for use by {@link PackageTracker}.
+ */
+final class PackageTrackerHelperImpl implements ClockHelper, ConfigHelper, PackageManagerHelper {
+
+    private static final String TAG = "PackageTrackerHelperImpl";
+
+    private final Context mContext;
+    private final PackageManager mPackageManager;
+
+    PackageTrackerHelperImpl(Context context) {
+        mContext = context;
+        mPackageManager = context.getPackageManager();
+    }
+
+    @Override
+    public boolean isTrackingEnabled() {
+        return mContext.getResources().getBoolean(R.bool.config_timeZoneRulesUpdateTrackingEnabled);
+    }
+
+    @Override
+    public String getUpdateAppPackageName() {
+        return mContext.getResources().getString(R.string.config_timeZoneRulesUpdaterPackage);
+    }
+
+    @Override
+    public String getDataAppPackageName() {
+        Resources resources = mContext.getResources();
+        return resources.getString(R.string.config_timeZoneRulesDataPackage);
+    }
+
+    @Override
+    public int getCheckTimeAllowedMillis() {
+        return mContext.getResources().getInteger(
+                R.integer.config_timeZoneRulesCheckTimeMillisAllowed);
+    }
+
+    @Override
+    public int getFailedCheckRetryCount() {
+        return mContext.getResources().getInteger(R.integer.config_timeZoneRulesCheckRetryCount);
+    }
+
+    @Override
+    public long currentTimestamp() {
+        // Use of elapsedRealtime() because this is in-memory state and elapsedRealtime() shouldn't
+        // change if the system clock changes.
+        return SystemClock.elapsedRealtime();
+    }
+
+    @Override
+    public int getInstalledPackageVersion(String packageName)
+            throws PackageManager.NameNotFoundException {
+        int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+        PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+        return packageInfo.versionCode;
+    }
+
+    @Override
+    public boolean isPrivilegedApp(String packageName) throws PackageManager.NameNotFoundException {
+        int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+        PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+        return packageInfo.applicationInfo.isPrivilegedApp();
+    }
+
+    @Override
+    public boolean usesPermission(String packageName, String requiredPermissionName)
+            throws PackageManager.NameNotFoundException {
+        int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+                | PackageManager.GET_PERMISSIONS;
+        PackageInfo packageInfo = mPackageManager.getPackageInfo(packageName, flags);
+        if (packageInfo.requestedPermissions == null) {
+            return false;
+        }
+        for (String requestedPermission : packageInfo.requestedPermissions) {
+            if (requiredPermissionName.equals(requestedPermission)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean contentProviderRegistered(String authority, String requiredPackageName) {
+        int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+        ProviderInfo providerInfo =
+                mPackageManager.resolveContentProvider(authority, flags);
+        if (providerInfo == null) {
+            Slog.i(TAG, "contentProviderRegistered: No content provider registered with authority="
+                    + authority);
+            return false;
+        }
+        boolean packageMatches =
+                requiredPackageName.equals(providerInfo.applicationInfo.packageName);
+        if (!packageMatches) {
+            Slog.i(TAG, "contentProviderRegistered: App with packageName=" + requiredPackageName
+                    + " does not expose the a content provider with authority=" + authority);
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public boolean receiverRegistered(Intent intent, String requiredPermissionName)
+            throws PackageManager.NameNotFoundException {
+
+        int flags = PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS;
+        List<ResolveInfo> resolveInfo = mPackageManager.queryBroadcastReceivers(intent, flags);
+        if (resolveInfo.size() != 1) {
+            Slog.i(TAG, "receiverRegistered: Zero or multiple broadcast receiver registered for"
+                    + " intent=" + intent + ", found=" + resolveInfo);
+            return false;
+        }
+
+        ResolveInfo matched = resolveInfo.get(0);
+        boolean requiresPermission = requiredPermissionName.equals(matched.activityInfo.permission);
+        if (!requiresPermission) {
+            Slog.i(TAG, "receiverRegistered: Broadcast receiver registered for intent="
+                    + intent + " must require permission " + requiredPermissionName);
+        }
+        return requiresPermission;
+    }
+}
diff --git a/services/core/java/com/android/server/timezone/PackageVersions.java b/services/core/java/com/android/server/timezone/PackageVersions.java
new file mode 100644
index 0000000..fc0d6e1
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/PackageVersions.java
@@ -0,0 +1,63 @@
+/*
+ * 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.server.timezone;
+
+/**
+ * Package version information about the time zone updater and time zone data application packages.
+ */
+final class PackageVersions {
+
+    final int mUpdateAppVersion;
+    final int mDataAppVersion;
+
+    PackageVersions(int updateAppVersion, int dataAppVersion) {
+        this.mUpdateAppVersion = updateAppVersion;
+        this.mDataAppVersion = dataAppVersion;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        PackageVersions that = (PackageVersions) o;
+
+        if (mUpdateAppVersion != that.mUpdateAppVersion) {
+            return false;
+        }
+        return mDataAppVersion == that.mDataAppVersion;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = mUpdateAppVersion;
+        result = 31 * result + mDataAppVersion;
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return "PackageVersions{" +
+                "mUpdateAppVersion=" + mUpdateAppVersion +
+                ", mDataAppVersion=" + mDataAppVersion +
+                '}';
+    }
+}
diff --git a/core/java/android/app/CompatibilityDisplayProperties.aidl b/services/core/java/com/android/server/timezone/PermissionHelper.java
similarity index 69%
copy from core/java/android/app/CompatibilityDisplayProperties.aidl
copy to services/core/java/com/android/server/timezone/PermissionHelper.java
index 626a63e..ba91c7f 100644
--- a/core/java/android/app/CompatibilityDisplayProperties.aidl
+++ b/services/core/java/com/android/server/timezone/PermissionHelper.java
@@ -14,7 +14,12 @@
  * limitations under the License.
  */
 
-package android.app;
+package com.android.server.timezone;
 
-/** @hide */
-parcelable CompatibilityDisplayProperties;
+/**
+ * An easy-to-mock interface around permission checks for use by {@link RulesManagerService}.
+ */
+public interface PermissionHelper {
+
+    void enforceCallerHasPermission(String requiredPermission) throws SecurityException;
+}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
new file mode 100644
index 0000000..82bd356
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -0,0 +1,348 @@
+/*
+ * 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.server.timezone;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.SystemService;
+
+import android.app.timezone.Callback;
+import android.app.timezone.DistroFormatVersion;
+import android.app.timezone.DistroRulesVersion;
+import android.app.timezone.ICallback;
+import android.app.timezone.IRulesManager;
+import android.app.timezone.RulesManager;
+import android.app.timezone.RulesState;
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.concurrent.Executor;
+import java.util.concurrent.atomic.AtomicBoolean;
+import libcore.tzdata.shared2.DistroException;
+import libcore.tzdata.shared2.DistroVersion;
+import libcore.tzdata.shared2.StagedDistroOperation;
+import libcore.tzdata.update2.TimeZoneDistroInstaller;
+
+// TODO(nfuller) Add EventLog calls where useful in the system server.
+// TODO(nfuller) Check logging best practices in the system server.
+// TODO(nfuller) Check error handling best practices in the system server.
+public final class RulesManagerService extends IRulesManager.Stub {
+
+    private static final String TAG = "timezone.RulesManagerService";
+
+    /** The distro format supported by this device. */
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    static final DistroFormatVersion DISTRO_FORMAT_VERSION_SUPPORTED =
+            new DistroFormatVersion(
+                    DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                    DistroVersion.CURRENT_FORMAT_MINOR_VERSION);
+
+    public static class Lifecycle extends SystemService {
+        private RulesManagerService mService;
+
+        public Lifecycle(Context context) {
+            super(context);
+        }
+
+        @Override
+        public void onStart() {
+            mService = RulesManagerService.create(getContext());
+            mService.start();
+
+            publishBinderService(Context.TIME_ZONE_RULES_MANAGER_SERVICE, mService);
+        }
+    }
+
+    @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+    static final String REQUIRED_UPDATER_PERMISSION =
+            android.Manifest.permission.UPDATE_TIME_ZONE_RULES;
+    private static final File SYSTEM_TZ_DATA_FILE = new File("/system/usr/share/zoneinfo/tzdata");
+    private static final File TZ_DATA_DIR = new File("/data/misc/zoneinfo");
+
+    private final AtomicBoolean mOperationInProgress = new AtomicBoolean(false);
+    private final PermissionHelper mPermissionHelper;
+    private final PackageTracker mPackageTracker;
+    private final Executor mExecutor;
+    private final TimeZoneDistroInstaller mInstaller;
+    private final FileDescriptorHelper mFileDescriptorHelper;
+
+    private static RulesManagerService create(Context context) {
+        RulesManagerServiceHelperImpl helper = new RulesManagerServiceHelperImpl(context);
+        return new RulesManagerService(
+                helper /* permissionHelper */,
+                helper /* executor */,
+                helper /* fileDescriptorHelper */,
+                PackageTracker.create(context),
+                new TimeZoneDistroInstaller(TAG, SYSTEM_TZ_DATA_FILE, TZ_DATA_DIR));
+    }
+
+    // A constructor that can be used by tests to supply mocked / faked dependencies.
+    RulesManagerService(PermissionHelper permissionHelper,
+            Executor executor,
+            FileDescriptorHelper fileDescriptorHelper, PackageTracker packageTracker,
+            TimeZoneDistroInstaller timeZoneDistroInstaller) {
+        mPermissionHelper = permissionHelper;
+        mExecutor = executor;
+        mFileDescriptorHelper = fileDescriptorHelper;
+        mPackageTracker = packageTracker;
+        mInstaller = timeZoneDistroInstaller;
+    }
+
+    public void start() {
+        mPackageTracker.start();
+    }
+
+    @Override // Binder call
+    public RulesState getRulesState() {
+        mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
+
+        synchronized(this) {
+            String systemRulesVersion;
+            try {
+                systemRulesVersion = mInstaller.getSystemRulesVersion();
+            } catch (IOException e) {
+                Slog.w(TAG, "Failed to read system rules", e);
+                return null;
+            }
+
+            boolean operationInProgress = this.mOperationInProgress.get();
+
+            // Determine the staged operation status, if possible.
+            DistroRulesVersion stagedDistroRulesVersion = null;
+            int stagedOperationStatus = RulesState.STAGED_OPERATION_UNKNOWN;
+            if (!operationInProgress) {
+                StagedDistroOperation stagedDistroOperation;
+                try {
+                    stagedDistroOperation = mInstaller.getStagedDistroOperation();
+                    if (stagedDistroOperation == null) {
+                        stagedOperationStatus = RulesState.STAGED_OPERATION_NONE;
+                    } else if (stagedDistroOperation.isUninstall) {
+                        stagedOperationStatus = RulesState.STAGED_OPERATION_UNINSTALL;
+                    } else {
+                        // Must be an install.
+                        stagedOperationStatus = RulesState.STAGED_OPERATION_INSTALL;
+                        DistroVersion stagedDistroVersion = stagedDistroOperation.distroVersion;
+                        stagedDistroRulesVersion = new DistroRulesVersion(
+                                stagedDistroVersion.rulesVersion,
+                                stagedDistroVersion.revision);
+                    }
+                } catch (DistroException | IOException e) {
+                    Slog.w(TAG, "Failed to read staged distro.", e);
+                }
+            }
+
+            // Determine the installed distro state, if possible.
+            DistroVersion installedDistroVersion;
+            int distroStatus = RulesState.DISTRO_STATUS_UNKNOWN;
+            DistroRulesVersion installedDistroRulesVersion = null;
+            if (!operationInProgress) {
+                try {
+                    installedDistroVersion = mInstaller.getInstalledDistroVersion();
+                    if (installedDistroVersion == null) {
+                        distroStatus = RulesState.DISTRO_STATUS_NONE;
+                        installedDistroRulesVersion = null;
+                    } else {
+                        distroStatus = RulesState.DISTRO_STATUS_INSTALLED;
+                        installedDistroRulesVersion = new DistroRulesVersion(
+                                installedDistroVersion.rulesVersion,
+                                installedDistroVersion.revision);
+                    }
+                } catch (DistroException | IOException e) {
+                    Slog.w(TAG, "Failed to read installed distro.", e);
+                }
+            }
+            return new RulesState(systemRulesVersion, DISTRO_FORMAT_VERSION_SUPPORTED,
+                    operationInProgress, stagedOperationStatus, stagedDistroRulesVersion,
+                    distroStatus, installedDistroRulesVersion);
+        }
+    }
+
+    @Override
+    public int requestInstall(
+            ParcelFileDescriptor timeZoneDistro, byte[] checkTokenBytes, ICallback callback) {
+        mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
+
+        CheckToken checkToken = null;
+        if (checkTokenBytes != null) {
+            checkToken = createCheckTokenOrThrow(checkTokenBytes);
+        }
+        synchronized (this) {
+            if (timeZoneDistro == null) {
+                throw new NullPointerException("timeZoneDistro == null");
+            }
+            if (callback == null) {
+                throw new NullPointerException("observer == null");
+            }
+            if (mOperationInProgress.get()) {
+                return RulesManager.ERROR_OPERATION_IN_PROGRESS;
+            }
+            mOperationInProgress.set(true);
+
+            // Execute the install asynchronously.
+            mExecutor.execute(new InstallRunnable(timeZoneDistro, checkToken, callback));
+
+            return RulesManager.SUCCESS;
+        }
+    }
+
+    private class InstallRunnable implements Runnable {
+
+        private final ParcelFileDescriptor mTimeZoneDistro;
+        private final CheckToken mCheckToken;
+        private final ICallback mCallback;
+
+        InstallRunnable(
+                ParcelFileDescriptor timeZoneDistro, CheckToken checkToken, ICallback callback) {
+            mTimeZoneDistro = timeZoneDistro;
+            mCheckToken = checkToken;
+            mCallback = callback;
+        }
+
+        @Override
+        public void run() {
+            // Adopt the ParcelFileDescriptor into this try-with-resources so it is closed
+            // when we are done.
+            boolean success = false;
+            try {
+                byte[] distroBytes =
+                        RulesManagerService.this.mFileDescriptorHelper.readFully(mTimeZoneDistro);
+                int installerResult = mInstaller.stageInstallWithErrorCode(distroBytes);
+                int resultCode = mapInstallerResultToApiCode(installerResult);
+                sendFinishedStatus(mCallback, resultCode);
+
+                // All the installer failure modes are currently non-recoverable and won't be
+                // improved by trying again. Therefore success = true.
+                success = true;
+            } catch (Exception e) {
+                Slog.w(TAG, "Failed to install distro.", e);
+                sendFinishedStatus(mCallback, Callback.ERROR_UNKNOWN_FAILURE);
+            } finally {
+                // Notify the package tracker that the operation is now complete.
+                mPackageTracker.recordCheckResult(mCheckToken, success);
+
+                mOperationInProgress.set(false);
+            }
+        }
+
+        private int mapInstallerResultToApiCode(int installerResult) {
+            switch (installerResult) {
+                case TimeZoneDistroInstaller.INSTALL_SUCCESS:
+                    return Callback.SUCCESS;
+                case TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_STRUCTURE:
+                    return Callback.ERROR_INSTALL_BAD_DISTRO_STRUCTURE;
+                case TimeZoneDistroInstaller.INSTALL_FAIL_RULES_TOO_OLD:
+                    return Callback.ERROR_INSTALL_RULES_TOO_OLD;
+                case TimeZoneDistroInstaller.INSTALL_FAIL_BAD_DISTRO_FORMAT_VERSION:
+                    return Callback.ERROR_INSTALL_BAD_DISTRO_FORMAT_VERSION;
+                case TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR:
+                    return Callback.ERROR_INSTALL_VALIDATION_ERROR;
+                default:
+                    return Callback.ERROR_UNKNOWN_FAILURE;
+            }
+        }
+    }
+
+    @Override
+    public int requestUninstall(byte[] checkTokenBytes, ICallback callback) {
+        mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
+
+        CheckToken checkToken = null;
+        if (checkTokenBytes != null) {
+            checkToken = createCheckTokenOrThrow(checkTokenBytes);
+        }
+        synchronized(this) {
+            if (callback == null) {
+                throw new NullPointerException("callback == null");
+            }
+
+            if (mOperationInProgress.get()) {
+                return RulesManager.ERROR_OPERATION_IN_PROGRESS;
+            }
+            mOperationInProgress.set(true);
+
+            // Execute the uninstall asynchronously.
+            mExecutor.execute(new UninstallRunnable(checkToken, callback));
+
+            return RulesManager.SUCCESS;
+        }
+    }
+
+    private class UninstallRunnable implements Runnable {
+
+        private final CheckToken mCheckToken;
+        private final ICallback mCallback;
+
+        public UninstallRunnable(CheckToken checkToken, ICallback callback) {
+            mCheckToken = checkToken;
+            mCallback = callback;
+        }
+
+        @Override
+        public void run() {
+            boolean success = false;
+            try {
+                success = mInstaller.stageUninstall();
+                // Right now we just have success (0) / failure (1). All clients should be checking
+                // against SUCCESS. More granular failures may be added in future.
+                int resultCode = success ? Callback.SUCCESS
+                        : Callback.ERROR_UNKNOWN_FAILURE;
+                sendFinishedStatus(mCallback, resultCode);
+            } catch (Exception e) {
+                Slog.w(TAG, "Failed to uninstall distro.", e);
+                sendFinishedStatus(mCallback, Callback.ERROR_UNKNOWN_FAILURE);
+            } finally {
+                // Notify the package tracker that the operation is now complete.
+                mPackageTracker.recordCheckResult(mCheckToken, success);
+
+                mOperationInProgress.set(false);
+            }
+        }
+    }
+
+    private void sendFinishedStatus(ICallback callback, int resultCode) {
+        try {
+            callback.onFinished(resultCode);
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Unable to notify observer of result", e);
+        }
+    }
+
+    @Override
+    public void requestNothing(byte[] checkTokenBytes, boolean success) {
+        mPermissionHelper.enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
+        CheckToken checkToken = null;
+        if (checkTokenBytes != null) {
+            checkToken = createCheckTokenOrThrow(checkTokenBytes);
+        }
+        mPackageTracker.recordCheckResult(checkToken, success);
+    }
+
+    private static CheckToken createCheckTokenOrThrow(byte[] checkTokenBytes) {
+        CheckToken checkToken;
+        try {
+            checkToken = CheckToken.fromByteArray(checkTokenBytes);
+        } catch (IOException e) {
+            throw new IllegalArgumentException("Unable to read token bytes "
+                    + Arrays.toString(checkTokenBytes), e);
+        }
+        return checkToken;
+    }
+}
diff --git a/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
new file mode 100644
index 0000000..15a571d
--- /dev/null
+++ b/services/core/java/com/android/server/timezone/RulesManagerServiceHelperImpl.java
@@ -0,0 +1,59 @@
+/*
+ * 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.server.timezone;
+
+import android.content.Context;
+import android.os.ParcelFileDescriptor;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.concurrent.Executor;
+import libcore.io.Streams;
+
+/**
+ * A single class that implements multiple helper interfaces for use by {@link RulesManagerService}.
+ */
+final class RulesManagerServiceHelperImpl
+        implements PermissionHelper, Executor, FileDescriptorHelper {
+
+    private final Context mContext;
+
+    RulesManagerServiceHelperImpl(Context context) {
+        mContext = context;
+    }
+
+    @Override
+    public void enforceCallerHasPermission(String requiredPermission) {
+        mContext.enforceCallingPermission(requiredPermission, null /* message */);
+    }
+
+    // TODO Wake lock required?
+    @Override
+    public void execute(Runnable runnable) {
+        // TODO Is there a better way?
+        new Thread(runnable).start();
+    }
+
+    @Override
+    public byte[] readFully(ParcelFileDescriptor parcelFileDescriptor) throws IOException {
+        try (ParcelFileDescriptor pfd = parcelFileDescriptor) {
+            // Read bytes
+            FileInputStream in = new FileInputStream(pfd.getFileDescriptor(), false /* isOwner */);
+            return Streams.readFully(in);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 49b4563..5bd485c 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -332,8 +332,6 @@
                     agentInfo.label = resolveInfo.loadLabel(pm);
                     agentInfo.icon = resolveInfo.loadIcon(pm);
                     agentInfo.settings = getSettingsAttrs(pm, resolveInfo);
-                    agentInfo.agent = new TrustAgentWrapper(mContext, this,
-                            new Intent().setComponent(name), userInfo.getUserHandle());
                 } else {
                     int index = mActiveAgents.indexOf(agentInfo);
                     agentInfo = mActiveAgents.valueAt(index);
@@ -370,6 +368,11 @@
                     }
                 }
 
+                if (agentInfo.agent == null) {
+                    agentInfo.agent = new TrustAgentWrapper(mContext, this,
+                            new Intent().setComponent(name), userInfo.getUserHandle());
+                }
+
                 if (!mActiveAgents.contains(agentInfo)) {
                     mActiveAgents.add(agentInfo);
                 } else {
diff --git a/services/core/java/com/android/server/vr/VrManagerInternal.java b/services/core/java/com/android/server/vr/VrManagerInternal.java
index 63c6195..1f75640 100644
--- a/services/core/java/com/android/server/vr/VrManagerInternal.java
+++ b/services/core/java/com/android/server/vr/VrManagerInternal.java
@@ -16,7 +16,7 @@
 package com.android.server.vr;
 
 import android.annotation.NonNull;
-import android.app.CompatibilityDisplayProperties;
+import android.app.Vr2dDisplayProperties;
 import android.content.ComponentName;
 import android.service.vr.IPersistentVrStateCallbacks;
 
@@ -83,16 +83,16 @@
     public abstract int hasVrPackage(@NonNull ComponentName packageName, int userId);
 
     /**
-     * Sets the resolution and DPI of the compatibility virtual display used to display
+     * Sets the resolution and DPI of the vr2d virtual display used to display
      * 2D applications in VR mode.
      *
      * <p>Requires {@link android.Manifest.permission#ACCESS_VR_MANAGER} permission.</p>
      *
-     * @param compatDisplayProp Properties of the virtual display for 2D applications
+     * @param vr2dDisplayProp Properties of the virtual display for 2D applications
      * in VR mode.
      */
-    public abstract void setCompatibilityDisplayProperties(
-            CompatibilityDisplayProperties compatDisplayProp);
+    public abstract void setVr2dDisplayProperties(
+            Vr2dDisplayProperties vr2dDisplayProp);
 
     /**
      * Sets the persistent VR mode state of a device. When a device is in persistent VR mode it will
@@ -110,7 +110,7 @@
      * @return {@link android.view.Display.INVALID_DISPLAY} if there is no virtual display
      * currently, else return the display id of the virtual display
      */
-    public abstract int getCompatibilityDisplayId();
+    public abstract int getVr2dDisplayId();
 
     /**
      * Adds listener that reports state changes to persistent VR mode.
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 860b241..9ef7410 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -21,7 +21,7 @@
 import android.app.ActivityManagerInternal;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
-import android.app.CompatibilityDisplayProperties;
+import android.app.Vr2dDisplayProperties;
 import android.app.NotificationManager;
 import android.annotation.NonNull;
 import android.content.ComponentName;
@@ -39,7 +39,6 @@
 import android.os.Message;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
@@ -47,7 +46,6 @@
 import android.service.vr.IVrListener;
 import android.service.vr.IVrManager;
 import android.service.vr.IVrStateCallbacks;
-import android.service.vr.IVrWindowManager;
 import android.service.vr.VrListenerService;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -141,7 +139,7 @@
     private final NotificationAccessManager mNotifAccessManager = new NotificationAccessManager();
     /** Tracks the state of the screen and keyguard UI.*/
     private int mSystemSleepFlags = FLAG_AWAKE;
-    private CompatibilityDisplay mCompatibilityDisplay;
+    private Vr2dDisplay mVr2dDisplay;
 
     private static final int MSG_VR_STATE_CHANGE = 0;
     private static final int MSG_PENDING_VR_STATE_CHANGE = 1;
@@ -428,27 +426,15 @@
         }
 
         @Override
-        public void setCompatibilityDisplayProperties(
-                CompatibilityDisplayProperties compatDisplayProp) {
+        public void setVr2dDisplayProperties(
+                Vr2dDisplayProperties vr2dDisplayProp) {
             enforceCallerPermission(Manifest.permission.RESTRICTED_VR_ACCESS);
-            VrManagerService.this.setCompatibilityDisplayProperties(compatDisplayProp);
+            VrManagerService.this.setVr2dDisplayProperties(vr2dDisplayProp);
         }
 
         @Override
-        public int getCompatibilityDisplayId() {
-            return VrManagerService.this.getCompatibilityDisplayId();
-        }
-
-        @Override
-        public void connectController(FileDescriptor fd) throws android.os.RemoteException {
-            enforceCallerPermission(Manifest.permission.RESTRICTED_VR_ACCESS);
-            VrManagerService.this.connectController(fd);
-        }
-
-        @Override
-        public void disconnectController() throws android.os.RemoteException {
-            enforceCallerPermission(Manifest.permission.RESTRICTED_VR_ACCESS);
-            VrManagerService.this.disconnectController();
+        public int getVr2dDisplayId() {
+            return VrManagerService.this.getVr2dDisplayId();
         }
 
         @Override
@@ -549,14 +535,14 @@
         }
 
         @Override
-        public void setCompatibilityDisplayProperties(
-            CompatibilityDisplayProperties compatDisplayProp) {
-            VrManagerService.this.setCompatibilityDisplayProperties(compatDisplayProp);
+        public void setVr2dDisplayProperties(
+            Vr2dDisplayProperties compatDisplayProp) {
+            VrManagerService.this.setVr2dDisplayProperties(compatDisplayProp);
         }
 
         @Override
-        public int getCompatibilityDisplayId() {
-            return VrManagerService.this.getCompatibilityDisplayId();
+        public int getVr2dDisplayId() {
+            return VrManagerService.this.getVr2dDisplayId();
         }
 
         @Override
@@ -608,8 +594,8 @@
             DisplayManager dm =
                     (DisplayManager) getContext().getSystemService(Context.DISPLAY_SERVICE);
             ActivityManagerInternal ami = LocalServices.getService(ActivityManagerInternal.class);
-            mCompatibilityDisplay = new CompatibilityDisplay(dm, ami, mVrManager);
-            mCompatibilityDisplay.init(getContext());
+            mVr2dDisplay = new Vr2dDisplay(dm, ami, mVrManager);
+            mVr2dDisplay.init(getContext());
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             synchronized (mLock) {
                 mVrModeAllowed = true;
@@ -1116,20 +1102,20 @@
         }
     }
 
-    public void setCompatibilityDisplayProperties(
-        CompatibilityDisplayProperties compatDisplayProp) {
-        if (mCompatibilityDisplay != null) {
-            mCompatibilityDisplay.setVirtualDisplayProperties(compatDisplayProp);
+    public void setVr2dDisplayProperties(
+        Vr2dDisplayProperties compatDisplayProp) {
+        if (mVr2dDisplay != null) {
+            mVr2dDisplay.setVirtualDisplayProperties(compatDisplayProp);
             return;
         }
-        Slog.w(TAG, "CompatibilityDisplay is null!");
+        Slog.w(TAG, "Vr2dDisplay is null!");
     }
 
-    private int getCompatibilityDisplayId() {
-        if (mCompatibilityDisplay != null) {
-            return mCompatibilityDisplay.getVirtualDisplayId();
+    private int getVr2dDisplayId() {
+        if (mVr2dDisplay != null) {
+            return mVr2dDisplay.getVirtualDisplayId();
         }
-        Slog.w(TAG, "CompatibilityDisplay is null!");
+        Slog.w(TAG, "Vr2dDisplay is null!");
         return INVALID_DISPLAY;
     }
 
@@ -1184,20 +1170,4 @@
             return mVrModeEnabled;
         }
     }
-
-    private void connectController(FileDescriptor fd) throws android.os.RemoteException {
-        // TODO(b/36506799): move vr_wm code to VrCore and remove this.
-        IVrWindowManager remote =
-                IVrWindowManager.Stub.asInterface(
-                        ServiceManager.getService(IVrWindowManager.SERVICE_NAME));
-        remote.connectController(fd);
-    }
-
-    private void disconnectController() throws android.os.RemoteException {
-        // TODO(b/36506799): move vr_wm code to VrCore and remove this.
-        IVrWindowManager remote =
-                IVrWindowManager.Stub.asInterface(
-                        ServiceManager.getService(IVrWindowManager.SERVICE_NAME));
-        remote.disconnectController();
-    }
 }
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d572003..70782dd 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -52,9 +52,11 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.BitmapRegionDecoder;
+import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Environment;
@@ -165,6 +167,7 @@
     static final String WALLPAPER_LOCK_ORIG = "wallpaper_lock_orig";
     static final String WALLPAPER_LOCK_CROP = "wallpaper_lock";
     static final String WALLPAPER_INFO = "wallpaper_info.xml";
+    static final int MAX_WALLPAPER_EXTRACTION_AREA = 112 * 112;
 
     // All the various per-user state files we need to be aware of
     static final String[] sPerUserFiles = new String[] {
@@ -376,43 +379,89 @@
         }
     }
 
+    /**
+     * We can easily extract colors from an ImageWallpaper since it's only a bitmap.
+     * In this case, using the crop is more than enough.
+     *
+     * In case of a live wallpaper, the best we can do is to extract colors from its
+     * preview image. Anyway, the live wallpaper can also implement the wallpaper colors API
+     * to report when colors change.
+     *
+     * @param wallpaper a wallpaper representation
+     */
     private void extractColors(WallpaperData wallpaper) {
         String cropFile = null;
+        Drawable thumbnail = null;
+        // This represents a maximum pixel count in an image.
+        // It prevents color extraction on big bitmaps.
         int wallpaperId = -1;
-        synchronized (mLock) {
-            // Only extract colors of ImageWallpaper or lock wallpapers (null)
-            final boolean supportedComponent = mImageWallpaper.equals(wallpaper.wallpaperComponent)
-                    || wallpaper.wallpaperComponent == null;
-            if (!supportedComponent)
-                return;
 
-            if (wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
-                cropFile = wallpaper.cropFile.getAbsolutePath();
+        synchronized (mLock) {
+            final boolean imageWallpaper = mImageWallpaper.equals(wallpaper.wallpaperComponent)
+                    || wallpaper.wallpaperComponent == null;
+            if (imageWallpaper) {
+                if (wallpaper.cropFile != null && wallpaper.cropFile.exists()) {
+                    cropFile = wallpaper.cropFile.getAbsolutePath();
+                }
+            } else {
+                if (wallpaper.connection == null) {
+                    Slog.w(TAG, "Can't extract colors, wallpaper not connected. " +
+                            wallpaper.wallpaperId);
+                    return;
+                }
+                WallpaperInfo info = wallpaper.connection.mInfo;
+                if (info == null) {
+                    Slog.w(TAG, "Something is really wrong, live wallpaper doesn't have " +
+                           "a WallpaperInfo object! " + wallpaper.wallpaperId);
+                    return;
+                }
+                thumbnail = info.loadThumbnail(mContext.getPackageManager());
             }
+
             wallpaperId = wallpaper.wallpaperId;
         }
 
+        Bitmap bitmap = null;
         if (cropFile != null) {
-            final Bitmap bitmap = BitmapFactory.decodeFile(cropFile);
-            if (bitmap == null) {
-                Slog.w(TAG, "Cannot extract colors because wallpaper file could not be read.");
-                return;
+            bitmap = BitmapFactory.decodeFile(cropFile);
+        } else if (thumbnail != null) {
+            // Calculate how big the bitmap needs to be.
+            // This avoids unnecessary processing and allocation inside Palette.
+            final int requestedArea = thumbnail.getIntrinsicWidth() *
+                    thumbnail.getIntrinsicHeight();
+            double scale = 1;
+            if (requestedArea > MAX_WALLPAPER_EXTRACTION_AREA) {
+                scale = Math.sqrt(MAX_WALLPAPER_EXTRACTION_AREA / (double) requestedArea);
             }
-            Palette palette = Palette.from(bitmap).generate();
-            bitmap.recycle();
+            bitmap = Bitmap.createBitmap((int) (thumbnail.getIntrinsicWidth() * scale),
+                    (int) (thumbnail.getIntrinsicHeight() * scale), Bitmap.Config.ARGB_8888);
+            final Canvas bmpCanvas = new Canvas(bitmap);
+            thumbnail.setBounds(0, 0, bitmap.getWidth(), bitmap.getHeight());
+            thumbnail.draw(bmpCanvas);
+        }
 
-            final List<Pair<Color, Integer>> colors = new ArrayList<>();
-            for (Palette.Swatch swatch : palette.getSwatches()) {
-                colors.add(new Pair<>(Color.valueOf(swatch.getRgb()),
-                        swatch.getPopulation()));
-            }
+        if (bitmap == null) {
+            Slog.w(TAG, "Cannot extract colors because wallpaper could not be read.");
+            return;
+        }
 
-            synchronized (mLock) {
-                if (wallpaper.wallpaperId == wallpaperId) {
-                    wallpaper.primaryColors = new WallpaperColors(colors);
-                } else {
-                    Slog.w(TAG, "Not setting primary colors since wallpaper changed");
-                }
+        Palette palette = Palette
+                .from(bitmap)
+                .resizeBitmapArea(MAX_WALLPAPER_EXTRACTION_AREA)
+                .generate();
+        bitmap.recycle();
+
+        final List<Pair<Color, Integer>> colors = new ArrayList<>();
+        for (Palette.Swatch swatch : palette.getSwatches()) {
+            colors.add(new Pair<>(Color.valueOf(swatch.getRgb()),
+                    swatch.getPopulation()));
+        }
+
+        synchronized (mLock) {
+            if (wallpaper.wallpaperId == wallpaperId) {
+                wallpaper.primaryColors = new WallpaperColors(colors);
+            } else {
+                Slog.w(TAG, "Not setting primary colors since wallpaper changed");
             }
         }
     }
@@ -817,6 +866,11 @@
          */
         @Override
         public void onWallpaperColorsChanged(WallpaperColors primaryColors) {
+            // Do not override default color extraction if API isn't implemented.
+            if (primaryColors == null) {
+                return;
+            }
+
             int which;
             synchronized (mLock) {
                 // Do not broadcast changes on ImageWallpaper since it's handled
@@ -1262,13 +1316,22 @@
         userId = ActivityManager.handleIncomingUser(Binder.getCallingPid(),
                 Binder.getCallingUid(), userId, false, true, "clearWallpaper", null);
 
+        WallpaperData data = null;
         synchronized (mLock) {
             clearWallpaperLocked(false, which, userId, null);
+
+            if (which == FLAG_LOCK) {
+                data = mLockWallpaperMap.get(userId);
+            }
+            if (which == FLAG_SYSTEM || data == null) {
+                data = mWallpaperMap.get(userId);
+            }
         }
 
         // When clearing a wallpaper, broadcast new valid colors
-        WallpaperData data = getWallpaperSafeLocked(mCurrentUserId, which);
-        notifyWallpaperColorsChanged(data, which);
+        if (data != null) {
+            notifyWallpaperColorsChanged(data, which);
+        }
     }
 
     void clearWallpaperLocked(boolean defaultFailed, int which, int userId, IRemoteCallback reply) {
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 7a36da2..a38addb 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -54,6 +54,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Path;
 import android.graphics.Rect;
+import android.os.Binder;
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
@@ -1808,27 +1809,25 @@
             final IAppTransitionAnimationSpecsFuture future
                     = mNextAppTransitionAnimationsSpecsFuture;
             mNextAppTransitionAnimationsSpecsFuture = null;
-            mDefaultExecutor.execute(new Runnable() {
-                @Override
-                public void run() {
-                    AppTransitionAnimationSpec[] specs = null;
-                    try {
-                        specs = future.get();
-                    } catch (RemoteException e) {
-                        Slog.w(TAG, "Failed to fetch app transition specs: " + e);
-                    }
-                    synchronized (mService.mWindowMap) {
-                        mNextAppTransitionAnimationsSpecsPending = false;
-                        overridePendingAppTransitionMultiThumb(specs,
-                                mNextAppTransitionFutureCallback, null /* finishedCallback */,
-                                mNextAppTransitionScaleUp);
-                        mNextAppTransitionFutureCallback = null;
-                        if (specs != null) {
-                            mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
-                        }
-                    }
-                    mService.requestTraversal();
+            mDefaultExecutor.execute(() -> {
+                AppTransitionAnimationSpec[] specs = null;
+                try {
+                    Binder.allowBlocking(future.asBinder());
+                    specs = future.get();
+                } catch (RemoteException e) {
+                    Slog.w(TAG, "Failed to fetch app transition specs: " + e);
                 }
+                synchronized (mService.mWindowMap) {
+                    mNextAppTransitionAnimationsSpecsPending = false;
+                    overridePendingAppTransitionMultiThumb(specs,
+                            mNextAppTransitionFutureCallback, null /* finishedCallback */,
+                            mNextAppTransitionScaleUp);
+                    mNextAppTransitionFutureCallback = null;
+                    if (specs != null) {
+                        mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
+                    }
+                }
+                mService.requestTraversal();
             });
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index be242b6..c59065f 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -759,16 +759,25 @@
         return token.asAppWindowToken();
     }
 
-    void addWindowToken(IBinder binder, WindowToken token) {
+    private void addWindowToken(IBinder binder, WindowToken token) {
         final DisplayContent dc = mService.mRoot.getWindowTokenDisplay(token);
         if (dc != null) {
             // We currently don't support adding a window token to the display if the display
             // already has the binder mapped to another token. If there is a use case for supporting
             // this moving forward we will either need to merge the WindowTokens some how or have
             // the binder map to a list of window tokens.
-            throw new IllegalArgumentException("Can't map token=" + token + " to display=" + this
-                    + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
+            throw new IllegalArgumentException("Can't map token=" + token + " to display="
+                    + getName() + " already mapped to display=" + dc + " tokens=" + dc.mTokenMap);
         }
+        if (binder == null) {
+            throw new IllegalArgumentException("Can't map token=" + token + " to display="
+                    + getName() + " binder is null");
+        }
+        if (token == null) {
+            throw new IllegalArgumentException("Can't map null token to display="
+                    + getName() + " binder=" + binder);
+        }
+
         mTokenMap.put(binder, token);
 
         if (token.asAppWindowToken() == null) {
@@ -1503,16 +1512,8 @@
         return mImeWindowsContainers.forAllWindows(callback, traverseTopToBottom);
     }
 
-    /**
-     * Returns the orientation that this display should be in factoring in its children containers.
-     *
-     * @param includeAppContainers True if then app containers (stacks, tasks, ...) should be
-     *                             factored in when determining the orientation. If false only
-     *                             non-app/system containers will be used to determine the returned
-     *                             orientation.
-     * @return The orientation the display should be in.
-     */
-    int getOrientation(boolean includeAppContainers) {
+    @Override
+    int getOrientation() {
         final WindowManagerPolicy policy = mService.mPolicy;
 
         if (mService.mDisplayFrozen) {
@@ -1541,14 +1542,8 @@
             }
         }
 
-        // Top system windows are not requesting an orientation. Get orientation from app containers
-        // if allowed. Otherwise, return the last orientation.
-        return includeAppContainers ? mTaskStackContainers.getOrientation() : mLastOrientation;
-    }
-
-    @Override
-    int getOrientation() {
-        return getOrientation(true /* includeAppContainers */);
+        // Top system windows are not requesting an orientation. Start searching from apps.
+        return mTaskStackContainers.getOrientation();
     }
 
     void updateDisplayInfo() {
@@ -2891,21 +2886,6 @@
         final Rect frame = new Rect();
         final Rect stackBounds = new Rect();
 
-        boolean includeImeInScreenshot;
-        synchronized(mService.mWindowMap) {
-            final AppWindowToken imeTargetAppToken = mService.mInputMethodTarget != null
-                    ? mService.mInputMethodTarget.mAppToken : null;
-            // We only include the Ime in the screenshot if the app we are screenshoting is the IME
-            // target and isn't in multi-window mode. We don't screenshot the IME in multi-window
-            // mode because the frame of the IME might not overlap with that of the app.
-            // E.g. IME target app at the top in split-screen mode and the IME at the bottom
-            // overlapping with the bottom app.
-            includeImeInScreenshot = imeTargetAppToken != null
-                    && imeTargetAppToken.appToken != null
-                    && imeTargetAppToken.appToken.asBinder() == appToken
-                    && !mService.mInputMethodTarget.isInMultiWindowMode();
-        }
-
         final int aboveAppLayer = (mService.mPolicy.getWindowLayerFromTypeLw(TYPE_APPLICATION) + 1)
                 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
         final MutableBoolean mutableIncludeFullDisplay = new MutableBoolean(includeFullDisplay);
@@ -2923,9 +2903,7 @@
                     return false;
                 }
                 if (w.mIsImWindow) {
-                    if (!includeImeInScreenshot) {
-                        return false;
-                    }
+                    return false;
                 } else if (w.mIsWallpaper) {
                     // If this is the wallpaper layer and we're only looking for the wallpaper layer
                     // then the target window state is this one.
@@ -2965,27 +2943,29 @@
                 }
 
                 // Don't include wallpaper in bounds calculation
-                if (!mutableIncludeFullDisplay.value && includeDecor) {
-                    final TaskStack stack = w.getStack();
-                    if (stack != null) {
-                        stack.getBounds(frame);
-                    }
+                if (!w.mIsWallpaper && !mutableIncludeFullDisplay.value) {
+                    if (includeDecor) {
+                        final TaskStack stack = w.getStack();
+                        if (stack != null) {
+                            stack.getBounds(frame);
+                        }
 
-                    // We want to screenshot with the exact bounds of the surface of the app. Thus,
-                    // intersect it with the frame.
-                    frame.intersect(w.mFrame);
-                }else if (!mutableIncludeFullDisplay.value && !w.mIsWallpaper) {
-                    final Rect wf = w.mFrame;
-                    final Rect cr = w.mContentInsets;
-                    int left = wf.left + cr.left;
-                    int top = wf.top + cr.top;
-                    int right = wf.right - cr.right;
-                    int bottom = wf.bottom - cr.bottom;
-                    frame.union(left, top, right, bottom);
-                    w.getVisibleBounds(stackBounds);
-                    if (!Rect.intersects(frame, stackBounds)) {
-                        // Set frame empty if there's no intersection.
-                        frame.setEmpty();
+                        // We want to screenshot with the exact bounds of the surface of the app. Thus,
+                        // intersect it with the frame.
+                        frame.intersect(w.mFrame);
+                    } else {
+                        final Rect wf = w.mFrame;
+                        final Rect cr = w.mContentInsets;
+                        int left = wf.left + cr.left;
+                        int top = wf.top + cr.top;
+                        int right = wf.right - cr.right;
+                        int bottom = wf.bottom - cr.bottom;
+                        frame.union(left, top, right, bottom);
+                        w.getVisibleBounds(stackBounds);
+                        if (!Rect.intersects(frame, stackBounds)) {
+                            // Set frame empty if there's no intersection.
+                            frame.setEmpty();
+                        }
                     }
                 }
 
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
index f2a92df..e5c7a72 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotPersister.java
@@ -24,6 +24,7 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.CompressFormat;
+import android.graphics.Bitmap.Config;
 import android.os.Process;
 import android.os.SystemClock;
 import android.util.ArraySet;
@@ -266,12 +267,13 @@
             final File file = getBitmapFile(mTaskId, mUserId);
             final File reducedFile = getReducedResolutionBitmapFile(mTaskId, mUserId);
             final Bitmap bitmap = Bitmap.createHardwareBitmap(mSnapshot.getSnapshot());
-            final Bitmap reduced = Bitmap.createScaledBitmap(bitmap,
+            final Bitmap swBitmap = bitmap.copy(Config.ARGB_8888, false /* isMutable */);
+            final Bitmap reduced = Bitmap.createScaledBitmap(swBitmap,
                     (int) (bitmap.getWidth() * REDUCED_SCALE),
                     (int) (bitmap.getHeight() * REDUCED_SCALE), true /* filter */);
             try {
                 FileOutputStream fos = new FileOutputStream(file);
-                bitmap.compress(JPEG, QUALITY, fos);
+                swBitmap.compress(JPEG, QUALITY, fos);
                 fos.close();
                 FileOutputStream reducedFos = new FileOutputStream(reducedFile);
                 reduced.compress(JPEG, QUALITY, reducedFos);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a48397b..63cc9bf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -1239,7 +1239,8 @@
                         return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                     }
                 }
-                token = new WindowToken(this, attrs.token, type, false, displayContent,
+                final IBinder binder = attrs.token != null ? attrs.token : client.asBinder();
+                token = new WindowToken(this, binder, type, false, displayContent,
                         session.mCanAddInternalSystemWindow);
             } else if (rootType >= FIRST_APPLICATION_WINDOW && rootType <= LAST_APPLICATION_WINDOW) {
                 atoken = token.asAppWindowToken();
@@ -1310,7 +1311,7 @@
                 // It is not valid to use an app token with other system types; we will
                 // instead make a new token for it (as if null had been passed in for the token).
                 attrs.token = null;
-                token = new WindowToken(this, null, type, false, displayContent,
+                token = new WindowToken(this, client.asBinder(), type, false, displayContent,
                         session.mCanAddInternalSystemWindow);
             }
 
@@ -2373,7 +2374,7 @@
         try {
             synchronized(mWindowMap) {
                 config = updateOrientationFromAppTokensLocked(currentConfig, freezeThisOneIfNeeded,
-                        displayId, true /* includeAppContainers */);
+                        displayId);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -2383,13 +2384,13 @@
     }
 
     private Configuration updateOrientationFromAppTokensLocked(Configuration currentConfig,
-            IBinder freezeThisOneIfNeeded, int displayId, boolean includeAppContainers) {
+            IBinder freezeThisOneIfNeeded, int displayId) {
         if (!mDisplayReady) {
             return null;
         }
         Configuration config = null;
 
-        if (updateOrientationFromAppTokensLocked(false, displayId, includeAppContainers)) {
+        if (updateOrientationFromAppTokensLocked(false, displayId)) {
             // If we changed the orientation but mOrientationChangeComplete is already true,
             // we used seamless rotation, and we don't need to freeze the screen.
             if (freezeThisOneIfNeeded != null && !mRoot.mOrientationChangeComplete) {
@@ -2427,11 +2428,6 @@
         return config;
     }
 
-    boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
-        return updateOrientationFromAppTokensLocked(inTransaction, displayId,
-                false /* includeAppContainers */);
-    }
-
     /**
      * Determine the new desired orientation of the display, returning a non-null new Configuration
      * if it has changed from the current orientation.  IF TRUE IS RETURNED SOMEONE MUST CALL
@@ -2442,25 +2438,13 @@
      * The orientation is computed from non-application windows first. If none of the
      * non-application windows specify orientation, the orientation is computed from application
      * tokens.
-     *
-     * @param inTransaction True if we are currently in a surface transaction.
-     * @param displayId Id of the display to update orientation for.
-     * @param includeAppContainers True if then app containers (stacks, tasks, ...) should be
-     *                             factored in when determining the orientation. If false only
-     *                             non-app/system containers will be used to determine the returned
-     *                             orientation.
-     *                             NOTE: Only call originating from activity manager are expected to
-     *                             set this to true as it needs to synchronize several app states
-     *                             like visibility with the update of display orientation.
-     * @return True if the display orientation was updated.
      * @see android.view.IWindowManager#updateOrientationFromAppTokens(Configuration, IBinder, int)
      */
-    private boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId,
-            boolean includeAppContainers) {
-        final long ident = Binder.clearCallingIdentity();
+    boolean updateOrientationFromAppTokensLocked(boolean inTransaction, int displayId) {
+        long ident = Binder.clearCallingIdentity();
         try {
             final DisplayContent dc = mRoot.getDisplayContent(displayId);
-            final int req = dc.getOrientation(includeAppContainers);
+            final int req = dc.getOrientation();
             if (req != dc.getLastOrientation()) {
                 dc.setLastOrientation(req);
                 //send a message to Policy indicating orientation change to take
diff --git a/services/core/jni/JavaRef.cpp b/services/core/jni/JavaRef.cpp
index 4a9cdd9..ad07afa 100644
--- a/services/core/jni/JavaRef.cpp
+++ b/services/core/jni/JavaRef.cpp
@@ -23,24 +23,8 @@
 
 namespace android {
 
-JavaRef make_javaref(JNIEnv *env, jobject ref) {
-    ALOGV("wrapping %p", ref);
-    ALOGE_IF(env == nullptr, "Environment is a nullptr");
-
-    return JavaRef(ref, [env](jobject ref) {
-        ALOGV("deleting %p", ref);
-        if (env && ref) {
-            env->DeleteLocalRef(ref);
-        }
-    });
-}
-
 EnvWrapper::EnvWrapper(JNIEnv *env) : mEnv(env) {
     ALOGE_IF(env == nullptr, "Environment is a nullptr");
 }
 
-JavaRef EnvWrapper::operator() (jobject ref) const {
-    return make_javaref(mEnv, ref);
-}
-
 } // namespace android
diff --git a/services/core/jni/JavaRef.h b/services/core/jni/JavaRef.h
index c25f289..8a572e2 100644
--- a/services/core/jni/JavaRef.h
+++ b/services/core/jni/JavaRef.h
@@ -21,17 +21,30 @@
 #include <functional>
 #include <jni.h>
 #include <memory>
+#include <type_traits>
 
 namespace android {
 
-typedef std::unique_ptr<_jobject, std::function<void(jobject)>> JavaRef;
+template <typename T>
+using JavaRef = std::unique_ptr<typename std::remove_pointer<T>::type, std::function<void(T)>>;
 
-JavaRef make_javaref(JNIEnv *env, jobject ref);
+template <typename T>
+JavaRef<T> make_javaref(JNIEnv *env, T ref) {
+    return JavaRef<T>(ref, [env](T ref) {
+        if (env && ref) {
+            env->DeleteLocalRef(ref);
+        }
+    });
+}
 
 class EnvWrapper {
 public:
     EnvWrapper(JNIEnv *env);
-    JavaRef operator() (jobject ref) const;
+
+    template <typename T>
+    JavaRef<T> operator() (T ref) const {
+        return make_javaref(mEnv, ref);
+    }
 
 private:
     JNIEnv *mEnv;
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 0006110..14a2381 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -36,6 +36,7 @@
 #include <utils/Log.h>
 #include <utils/Looper.h>
 #include <utils/threads.h>
+#include <utils/SortedVector.h>
 
 #include <input/PointerController.h>
 #include <input/SpriteController.h>
@@ -206,6 +207,7 @@
     void setInputDispatchMode(bool enabled, bool frozen);
     void setSystemUiVisibility(int32_t visibility);
     void setPointerSpeed(int32_t speed);
+    void setInputDeviceEnabled(uint32_t deviceId, bool enabled);
     void setShowTouches(bool enabled);
     void setInteractive(bool interactive);
     void reloadCalibration();
@@ -290,6 +292,9 @@
 
         // Pointer controller singleton, created and destroyed as needed.
         wp<PointerController> pointerController;
+
+        // Input devices to be disabled
+        SortedVector<int32_t> disabledInputDevices;
     } mLocked;
 
     std::atomic<bool> mInteractive;
@@ -475,6 +480,8 @@
 
         outConfig->setDisplayInfo(false /*external*/, mLocked.internalViewport);
         outConfig->setDisplayInfo(true /*external*/, mLocked.externalViewport);
+
+        outConfig->disabledDevices = mLocked.disabledInputDevices;
     } // release lock
 }
 
@@ -764,6 +771,24 @@
             InputReaderConfiguration::CHANGE_POINTER_SPEED);
 }
 
+void NativeInputManager::setInputDeviceEnabled(uint32_t deviceId, bool enabled) {
+    { // acquire lock
+        AutoMutex _l(mLock);
+
+        ssize_t index = mLocked.disabledInputDevices.indexOf(deviceId);
+        bool currentlyEnabled = index < 0;
+        if (!enabled && currentlyEnabled) {
+            mLocked.disabledInputDevices.add(deviceId);
+        }
+        if (enabled && !currentlyEnabled) {
+            mLocked.disabledInputDevices.remove(deviceId);
+        }
+    } // release lock
+
+    mInputManager->getReader()->requestRefreshConfiguration(
+            InputReaderConfiguration::CHANGE_ENABLED_STATE);
+}
+
 void NativeInputManager::setShowTouches(bool enabled) {
     { // acquire lock
         AutoMutex _l(mLock);
@@ -1335,6 +1360,7 @@
 static void nativeToggleCapsLock(JNIEnv* env, jclass /* clazz */,
          jlong ptr, jint deviceId) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
     im->getInputManager()->getReader()->toggleCapsLockState(deviceId);
 }
 
@@ -1355,6 +1381,7 @@
 static void nativeSetPointerCapture(JNIEnv* env, jclass /* clazz */, jlong ptr,
         jboolean enabled) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
     im->setPointerCapture(enabled);
 }
 
@@ -1416,6 +1443,7 @@
 
 static void nativeReloadCalibration(JNIEnv* env, jclass clazz, jlong ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
     im->reloadCalibration();
 }
 
@@ -1482,13 +1510,36 @@
     im->getInputManager()->getDispatcher()->monitor();
 }
 
+static jboolean nativeIsInputDeviceEnabled(JNIEnv* env /* env */,
+        jclass /* clazz */, jlong ptr, jint deviceId) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    return im->getInputManager()->getReader()->isInputDeviceEnabled(deviceId);
+}
+
+static void nativeEnableInputDevice(JNIEnv* /* env */,
+        jclass /* clazz */, jlong ptr, jint deviceId) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    im->setInputDeviceEnabled(deviceId, true);
+}
+
+static void nativeDisableInputDevice(JNIEnv* /* env */,
+        jclass /* clazz */, jlong ptr, jint deviceId) {
+    NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
+    im->setInputDeviceEnabled(deviceId, false);
+}
+
 static void nativeSetPointerIconType(JNIEnv* /* env */, jclass /* clazz */, jlong ptr, jint iconId) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
     im->setPointerIconType(iconId);
 }
 
 static void nativeReloadPointerIcons(JNIEnv* /* env */, jclass /* clazz */, jlong ptr) {
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
+
     im->reloadPointerIcons();
 }
 
@@ -1576,6 +1627,12 @@
             (void*) nativeDump },
     { "nativeMonitor", "(J)V",
             (void*) nativeMonitor },
+    { "nativeIsInputDeviceEnabled", "(JI)Z",
+            (void*) nativeIsInputDeviceEnabled },
+    { "nativeEnableInputDevice", "(JI)V",
+            (void*) nativeEnableInputDevice },
+    { "nativeDisableInputDevice", "(JI)V",
+            (void*) nativeDisableInputDevice },
     { "nativeSetPointerIconType", "(JI)V",
             (void*) nativeSetPointerIconType },
     { "nativeReloadPointerIcons", "(J)V",
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index 813dcf5..514e996 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -29,16 +29,46 @@
 
 namespace android {
 
-using ILight     = ::android::hardware::light::V2_0::ILight;
 using Brightness = ::android::hardware::light::V2_0::Brightness;
 using Flash      = ::android::hardware::light::V2_0::Flash;
-using Type       = ::android::hardware::light::V2_0::Type;
+using ILight     = ::android::hardware::light::V2_0::ILight;
 using LightState = ::android::hardware::light::V2_0::LightState;
 using Status     = ::android::hardware::light::V2_0::Status;
+using Type       = ::android::hardware::light::V2_0::Type;
 template<typename T>
 using Return     = ::android::hardware::Return<T>;
 
-static sp<ILight> gLight;
+class LightHal {
+private:
+    static sp<ILight> sLight;
+    static bool sLightInit;
+
+    LightHal() {}
+
+public:
+    static void disassociate() {
+        sLightInit = false;
+        sLight = nullptr;
+    }
+
+    static sp<ILight> associate() {
+        if ((sLight == nullptr && !sLightInit) ||
+                (sLight != nullptr && !sLight->ping().isOk())) {
+            // will return the hal if it exists the first time.
+            sLight = ILight::getService();
+            sLightInit = true;
+
+            if (sLight == nullptr) {
+                ALOGE("Unable to get ILight interface.");
+            }
+        }
+
+        return sLight;
+    }
+};
+
+sp<ILight> LightHal::sLight = nullptr;
+bool LightHal::sLightInit = false;
 
 static bool validate(jint light, jint flash, jint brightness) {
     bool valid = true;
@@ -103,7 +133,7 @@
         const LightState &state) {
     if (!ret.isOk()) {
         ALOGE("Failed to issue set light command.");
-        gLight = nullptr;
+        LightHal::disassociate();
         return;
     }
 
@@ -137,12 +167,9 @@
         return;
     }
 
-    if (gLight == nullptr || !gLight->ping().isOk()) {
-        gLight = ILight::getService();
-    }
+    sp<ILight> hal = LightHal::associate();
 
-    if (gLight == nullptr) {
-        ALOGE("Unable to get ILight interface.");
+    if (hal == nullptr) {
         return;
     }
 
@@ -152,7 +179,7 @@
 
     {
         ALOGD_IF_SLOW(50, "Excessive delay setting light");
-        Return<Status> ret = gLight->setLight(type, state);
+        Return<Status> ret = hal->setLight(type, state);
         processReturn(ret, type, state);
     }
 }
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 1bdcd7a..c722629 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -57,6 +57,7 @@
 
 static jobject gPowerManagerServiceObj;
 sp<IPower> gPowerHal = nullptr;
+bool gPowerHalExists = true;
 std::mutex gPowerHalMutex;
 static nsecs_t gLastEventTime[USER_ACTIVITY_EVENT_LAST + 1];
 
@@ -78,12 +79,13 @@
 // Check validity of current handle to the power HAL service, and call getService() if necessary.
 // The caller must be holding gPowerHalMutex.
 bool getPowerHal() {
-    if (gPowerHal == nullptr) {
+    if (gPowerHalExists && gPowerHal == nullptr) {
         gPowerHal = IPower::getService();
         if (gPowerHal != nullptr) {
             ALOGI("Loaded power HAL service");
         } else {
             ALOGI("Couldn't load power HAL service");
+            gPowerHalExists = false;
         }
     }
     return gPowerHal != nullptr;
diff --git a/services/core/jni/com_android_server_radio_RadioService.cpp b/services/core/jni/com_android_server_radio_RadioService.cpp
index a6bcdbb..c424d30 100644
--- a/services/core/jni/com_android_server_radio_RadioService.cpp
+++ b/services/core/jni/com_android_server_radio_RadioService.cpp
@@ -22,6 +22,7 @@
 #include "com_android_server_radio_Tuner.h"
 #include "com_android_server_radio_convert.h"
 
+#include <android/hardware/broadcastradio/1.1/IBroadcastRadio.h>
 #include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
 #include <core_jni_helpers.h>
 #include <utils/Log.h>
@@ -39,7 +40,6 @@
 namespace V1_1 = hardware::broadcastradio::V1_1;
 
 using V1_0::Class;
-using V1_0::IBroadcastRadio;
 using V1_0::Result;
 
 using V1_0::BandConfig;
@@ -57,7 +57,7 @@
 struct ServiceContext {
     ServiceContext() {}
 
-    sp<IBroadcastRadio> mModule;
+    sp<V1_0::IBroadcastRadio> mModule;
 
 private:
     DISALLOW_COPY_AND_ASSIGN(ServiceContext);
@@ -90,7 +90,7 @@
     delete ctx;
 }
 
-static sp<IBroadcastRadio> getModule(jlong nativeContext) {
+static sp<V1_0::IBroadcastRadio> getModule(jlong nativeContext) {
     ALOGV("getModule()");
     AutoMutex _l(gContextMutex);
     auto& ctx = getNativeContext(nativeContext);
@@ -106,9 +106,10 @@
         return nullptr;
     }
 
-    sp<IBroadcastRadio> module = nullptr;
+    sp<V1_0::IBroadcastRadio> module = nullptr;
     // TODO(b/36863239): not only AM/FM
-    factory->connectModule(Class::AM_FM, [&](Result retval, const sp<IBroadcastRadio>& result) {
+    factory->connectModule(Class::AM_FM, [&](Result retval,
+            const sp<V1_0::IBroadcastRadio>& result) {
         if (retval == Result::OK) {
             module = result;
         }
@@ -133,10 +134,19 @@
         return nullptr;
     }
 
+    HalRevision halRev;
+    if (V1_1::IBroadcastRadio::castFrom(module).withDefault(nullptr) != nullptr) {
+        ALOGI("Opening tuner with broadcast radio HAL 1.1");
+        halRev = HalRevision::V1_1;
+    } else {
+        ALOGI("Opening tuner with broadcast radio HAL 1.0");
+        halRev = HalRevision::V1_0;
+    }
+
     Region region;
     BandConfig bandConfigHal = convert::BandConfigToHal(env, bandConfig, region);
 
-    jobject tuner = env->NewObject(gTunerClass, gTunerCstor, callback, region);
+    jobject tuner = env->NewObject(gTunerClass, gTunerCstor, callback, halRev, region, withAudio);
     if (tuner == nullptr) {
         ALOGE("Unable to create new tuner object.");
         return nullptr;
@@ -184,7 +194,7 @@
     auto tunerClass = FindClassOrDie(env, "com/android/server/radio/Tuner");
     gTunerClass = MakeGlobalRefOrDie(env, tunerClass);
     gTunerCstor = GetMethodIDOrDie(env, tunerClass, "<init>",
-            "(Landroid/hardware/radio/ITunerCallback;I)V");
+            "(Landroid/hardware/radio/ITunerCallback;IIZ)V");
 
     auto serviceClass = FindClassOrDie(env, "com/android/server/radio/RadioService");
     gServiceClass = MakeGlobalRefOrDie(env, serviceClass);
diff --git a/services/core/jni/com_android_server_radio_Tuner.cpp b/services/core/jni/com_android_server_radio_Tuner.cpp
index 96e122d..5a91c37 100644
--- a/services/core/jni/com_android_server_radio_Tuner.cpp
+++ b/services/core/jni/com_android_server_radio_Tuner.cpp
@@ -77,12 +77,13 @@
     return getNativeContext(env->GetLongField(obj, gjni.Tuner.nativeContext));
 }
 
-static jlong nativeInit(JNIEnv *env, jobject obj, jobject clientCallback) {
+static jlong nativeInit(JNIEnv *env, jobject obj, jobject clientCallback, jint halRev) {
     ALOGV("nativeInit()");
     AutoMutex _l(gContextMutex);
 
     auto ctx = new TunerContext();
-    ctx->mNativeCallback = new TunerCallback(env, obj, clientCallback);
+    ctx->mNativeCallback = new TunerCallback(env, obj,
+            clientCallback, static_cast<HalRevision>(halRev));
 
     static_assert(sizeof(jlong) >= sizeof(ctx), "jlong is smaller than a pointer");
     return reinterpret_cast<jlong>(ctx);
@@ -159,14 +160,47 @@
     return convert::BandConfigFromHal(env, halConfig, region).release();
 }
 
+static void nativeStep(JNIEnv *env, jobject obj, jlong nativeContext,
+        bool directionDown, bool skipSubChannel) {
+    ALOGV("nativeStep()");
+    auto halTuner = getHalTuner(nativeContext);
+
+    auto dir = convert::DirectionToHal(directionDown);
+    convert::ThrowIfFailed(env, halTuner->step(dir, skipSubChannel));
+}
+
+static void nativeScan(JNIEnv *env, jobject obj, jlong nativeContext,
+        bool directionDown, bool skipSubChannel) {
+    ALOGV("nativeScan()");
+    auto halTuner = getHalTuner(nativeContext);
+
+    auto dir = convert::DirectionToHal(directionDown);
+    convert::ThrowIfFailed(env, halTuner->scan(dir, skipSubChannel));
+}
+
+static void nativeTune(JNIEnv *env, jobject obj, jlong nativeContext,
+        jint channel, jint subChannel) {
+    // TODO(b/36863239): implement
+    jniThrowException(env, "java/lang/RuntimeException", "not implemented yet");
+}
+
+static void nativeCancel(JNIEnv *env, jobject obj, jlong nativeContext) {
+    // TODO(b/36863239): implement
+    jniThrowException(env, "java/lang/RuntimeException", "not implemented yet");
+}
+
 static const JNINativeMethod gTunerMethods[] = {
-    { "nativeInit", "(Landroid/hardware/radio/ITunerCallback;)J", (void*)nativeInit },
+    { "nativeInit", "(Landroid/hardware/radio/ITunerCallback;I)J", (void*)nativeInit },
     { "nativeFinalize", "(J)V", (void*)nativeFinalize },
     { "nativeClose", "(J)V", (void*)nativeClose },
     { "nativeSetConfiguration", "(JLandroid/hardware/radio/RadioManager$BandConfig;)V",
             (void*)nativeSetConfiguration },
     { "nativeGetConfiguration", "(JI)Landroid/hardware/radio/RadioManager$BandConfig;",
             (void*)nativeGetConfiguration },
+    { "nativeStep", "(JZZ)V", (void*)nativeStep },
+    { "nativeScan", "(JZZ)V", (void*)nativeScan },
+    { "nativeTune", "(JII)V", (void*)nativeTune },
+    { "nativeCancel", "(J)V", (void*)nativeCancel },
 };
 
 } // namespace Tuner
diff --git a/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp b/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp
index 54dd7df..4986091 100644
--- a/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp
+++ b/services/core/jni/com_android_server_radio_Tuner_TunerCallback.cpp
@@ -49,10 +49,11 @@
 static struct {
     jmethodID onError;
     jmethodID onConfigurationChanged;
+    jmethodID onProgramInfoChanged;
 } gITunerCallbackMethods;
 
 // from frameworks/base/core/java/android/hardware/radio/RadioTuner.java
-enum class TunerError : int {
+enum class TunerError : jint {
     HARDWARE_FAILURE = 0,
     SERVER_DIED = 1,
     CANCELLED = 2,
@@ -60,8 +61,8 @@
     CONFIG = 4,
 };
 
-TunerCallback::TunerCallback(JNIEnv *env, jobject tuner, jobject clientCallback)
-        : mCallbackThread(gvm) {
+TunerCallback::TunerCallback(JNIEnv *env, jobject tuner, jobject clientCallback, HalRevision halRev)
+        : mCallbackThread(gvm), mHalRev(halRev) {
     ALOGV("TunerCallback()");
     mTuner = env->NewGlobalRef(tuner);
     mClientCallback = env->NewGlobalRef(clientCallback);
@@ -111,7 +112,35 @@
 }
 
 Return<void> TunerCallback::tuneComplete(Result result, const V1_0::ProgramInfo& info) {
-    ALOGE("Not implemented: tuneComplete");
+    ALOGV("tuneComplete(%d)", result);
+
+    if (mHalRev > HalRevision::V1_0) {
+        ALOGD("1.0 callback was ignored");
+        return Return<void>();
+    }
+
+    V1_1::ProgramInfo info_1_1 {
+        .base = info,
+    };
+    return tuneComplete_1_1(result, info_1_1);
+}
+
+Return<void> TunerCallback::tuneComplete_1_1(Result result, const V1_1::ProgramInfo& info) {
+    ALOGV("tuneComplete_1_1(%d)", result);
+
+    mCallbackThread.enqueue([result, info, this](JNIEnv *env) {
+        if (result == Result::OK) {
+            auto jInfo = convert::ProgramInfoFromHal(env, info);
+            if (jInfo == nullptr) return;
+            env->CallVoidMethod(mClientCallback, gITunerCallbackMethods.onProgramInfoChanged,
+                    jInfo.get());
+        } else {
+            TunerError cause = TunerError::CANCELLED;
+            if (result == Result::TIMEOUT) cause = TunerError::SCAN_TIMEOUT;
+            env->CallVoidMethod(mClientCallback, gITunerCallbackMethods.onError, cause);
+        }
+    });
+
     return Return<void>();
 }
 
@@ -120,6 +149,11 @@
     return Return<void>();
 }
 
+Return<void> TunerCallback::afSwitch_1_1(const V1_1::ProgramInfo& info) {
+    ALOGE("Not implemented: afSwitch_1_1");
+    return Return<void>();
+}
+
 Return<void> TunerCallback::antennaStateChange(bool connected) {
     ALOGE("Not implemented: antennaStateChange");
     return Return<void>();
@@ -141,16 +175,6 @@
     return Return<void>();
 }
 
-Return<void> TunerCallback::tuneComplete_1_1(Result result, const V1_1::ProgramInfo& info) {
-    ALOGE("Not implemented: tuneComplete_1_1");
-    return Return<void>();
-}
-
-Return<void> TunerCallback::afSwitch_1_1(const V1_1::ProgramInfo& info) {
-    ALOGE("Not implemented: afSwitch_1_1afSwitch_1_1");
-    return Return<void>();
-}
-
 Return<void> TunerCallback::backgroundScanAvailable(bool isAvailable) {
     ALOGE("Not implemented: backgroundScanAvailable");
     return Return<void>();
@@ -180,6 +204,8 @@
     gITunerCallbackMethods.onError = GetMethodIDOrDie(env, gITunerCallbackClass, "onError", "(I)V");
     gITunerCallbackMethods.onConfigurationChanged = GetMethodIDOrDie(env, gITunerCallbackClass,
             "onConfigurationChanged", "(Landroid/hardware/radio/RadioManager$BandConfig;)V");
+    gITunerCallbackMethods.onProgramInfoChanged = GetMethodIDOrDie(env, gITunerCallbackClass,
+            "onProgramInfoChanged", "(Landroid/hardware/radio/RadioManager$ProgramInfo;)V");
 }
 
 } // namespace android
diff --git a/services/core/jni/com_android_server_radio_Tuner_TunerCallback.h b/services/core/jni/com_android_server_radio_Tuner_TunerCallback.h
index 1c680b8..31208e9 100644
--- a/services/core/jni/com_android_server_radio_Tuner_TunerCallback.h
+++ b/services/core/jni/com_android_server_radio_Tuner_TunerCallback.h
@@ -18,6 +18,7 @@
 #define _ANDROID_SERVER_RADIO_TUNER_TUNERCALLBACK_H
 
 #include "NativeCallbackThread.h"
+#include "com_android_server_radio_types.h"
 
 #include <android/hardware/broadcastradio/1.1/ITunerCallback.h>
 #include <jni.h>
@@ -34,11 +35,12 @@
     jobject mTuner;
     jobject mClientCallback;
     NativeCallbackThread mCallbackThread;
+    HalRevision mHalRev;
 
     DISALLOW_COPY_AND_ASSIGN(TunerCallback);
 
 public:
-    TunerCallback(JNIEnv *env, jobject tuner, jobject clientCallback);
+    TunerCallback(JNIEnv *env, jobject tuner, jobject clientCallback, HalRevision halRev);
     virtual ~TunerCallback();
 
     void detach();
diff --git a/services/core/jni/com_android_server_radio_convert.cpp b/services/core/jni/com_android_server_radio_convert.cpp
index 419e6d6..683f0ee 100644
--- a/services/core/jni/com_android_server_radio_convert.cpp
+++ b/services/core/jni/com_android_server_radio_convert.cpp
@@ -33,6 +33,8 @@
 
 using V1_0::Band;
 using V1_0::Deemphasis;
+using V1_0::Direction;
+using V1_0::MetadataType;
 using V1_0::Result;
 using V1_0::Rds;
 
@@ -62,6 +64,20 @@
         jfieldID upperLimit;
         jfieldID spacing;
     } BandDescriptor;
+
+    struct {
+        jclass clazz;
+        jmethodID cstor;
+    } ProgramInfo;
+
+    struct {
+        jclass clazz;
+        jmethodID cstor;
+        jmethodID putIntFromNative;
+        jmethodID putStringFromNative;
+        jmethodID putBitmapFromNative;
+        jmethodID putClockFromNative;
+    } RadioMetadata;
 } gjni;
 
 template <typename T>
@@ -137,7 +153,7 @@
     }
 }
 
-JavaRef BandConfigFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region) {
+JavaRef<jobject> BandConfigFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region) {
     ALOGV("BandConfigFromHal()");
     EnvWrapper wrap(env);
 
@@ -203,6 +219,77 @@
     return config;
 }
 
+Direction DirectionToHal(bool directionDown) {
+    return directionDown ? Direction::DOWN : Direction::UP;
+}
+
+static JavaRef<jobject> MetadataFromHal(JNIEnv *env, const hidl_vec<V1_0::MetaData> metadata) {
+    ALOGV("MetadataFromHal()");
+    EnvWrapper wrap(env);
+
+    if (metadata.size() == 0) return nullptr;
+
+    auto jMetadata = wrap(env->NewObject(gjni.RadioMetadata.clazz, gjni.RadioMetadata.cstor));
+
+    for (auto& item : metadata) {
+        jint key = static_cast<jint>(item.key);
+        jint status = 0;
+        switch (item.type) {
+            case MetadataType::INT:
+                ALOGV("metadata INT %d", key);
+                status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putIntFromNative,
+                        key, item.intValue);
+                break;
+            case MetadataType::TEXT: {
+                ALOGV("metadata TEXT %d", key);
+                auto value = wrap(env->NewStringUTF(item.stringValue.c_str()));
+                status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putStringFromNative,
+                        key, value.get());
+                break;
+            }
+            case MetadataType::RAW: {
+                ALOGV("metadata RAW %d", key);
+                auto len = item.rawValue.size();
+                if (len == 0) break;
+                auto value = wrap(env->NewByteArray(len));
+                if (value == nullptr) {
+                    ALOGE("Failed to allocate byte array of len %zu", len);
+                    break;
+                }
+                env->SetByteArrayRegion(value.get(), 0, len,
+                        reinterpret_cast<const jbyte*>(item.rawValue.data()));
+                status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putBitmapFromNative,
+                        key, value.get());
+                break;
+            }
+            case MetadataType::CLOCK:
+                ALOGV("metadata CLOCK %d", key);
+                status = env->CallIntMethod(jMetadata.get(), gjni.RadioMetadata.putClockFromNative,
+                        key, item.clockValue.utcSecondsSinceEpoch,
+                        item.clockValue.timezoneOffsetInMinutes);
+                break;
+            default:
+                ALOGW("invalid metadata type %d", item.type);
+        }
+        ALOGE_IF(status != 0, "Failed inserting metadata %d (of type %d)", key, item.type);
+    }
+
+    return jMetadata;
+}
+
+JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_1::ProgramInfo &info11) {
+    ALOGV("ProgramInfoFromHal()");
+    EnvWrapper wrap(env);
+
+    auto& info10 = info11.base;
+    auto jMetadata = MetadataFromHal(env, info10.metadata);
+    auto jVendorExtension = wrap(env->NewStringUTF(info11.vendorExension.c_str()));
+
+    return wrap(env->NewObject(gjni.ProgramInfo.clazz, gjni.ProgramInfo.cstor, info10.channel,
+            info10.subChannel, info10.tuned, info10.stereo, info10.digital, info10.signalStrength,
+            jMetadata.get(), info11.flags, jVendorExtension.get()));
+}
+
 
 } // namespace convert
 } // namespace radio
@@ -239,6 +326,23 @@
     gjni.BandDescriptor.lowerLimit = GetFieldIDOrDie(env, bandDescriptorClass, "mLowerLimit", "I");
     gjni.BandDescriptor.upperLimit = GetFieldIDOrDie(env, bandDescriptorClass, "mUpperLimit", "I");
     gjni.BandDescriptor.spacing = GetFieldIDOrDie(env, bandDescriptorClass, "mSpacing", "I");
+
+    auto programInfoClass = FindClassOrDie(env, "android/hardware/radio/RadioManager$ProgramInfo");
+    gjni.ProgramInfo.clazz = MakeGlobalRefOrDie(env, programInfoClass);
+    gjni.ProgramInfo.cstor = GetMethodIDOrDie(env, programInfoClass, "<init>",
+            "(IIZZZILandroid/hardware/radio/RadioMetadata;ILjava/lang/String;)V");
+
+    auto radioMetadataClass = FindClassOrDie(env, "android/hardware/radio/RadioMetadata");
+    gjni.RadioMetadata.clazz = MakeGlobalRefOrDie(env, radioMetadataClass);
+    gjni.RadioMetadata.cstor = GetMethodIDOrDie(env, radioMetadataClass, "<init>", "()V");
+    gjni.RadioMetadata.putIntFromNative = GetMethodIDOrDie(env, radioMetadataClass,
+            "putIntFromNative", "(II)I");
+    gjni.RadioMetadata.putStringFromNative = GetMethodIDOrDie(env, radioMetadataClass,
+            "putStringFromNative", "(ILjava/lang/String;)I");
+    gjni.RadioMetadata.putBitmapFromNative = GetMethodIDOrDie(env, radioMetadataClass,
+            "putBitmapFromNative", "(I[B)I");
+    gjni.RadioMetadata.putClockFromNative = GetMethodIDOrDie(env, radioMetadataClass,
+            "putClockFromNative", "(IJI)I");
 }
 
 } // namespace android
diff --git a/services/core/jni/com_android_server_radio_convert.h b/services/core/jni/com_android_server_radio_convert.h
index dba948e..7b6e38d 100644
--- a/services/core/jni/com_android_server_radio_convert.h
+++ b/services/core/jni/com_android_server_radio_convert.h
@@ -34,12 +34,16 @@
 namespace V1_0 = hardware::broadcastradio::V1_0;
 namespace V1_1 = hardware::broadcastradio::V1_1;
 
-JavaRef BandConfigFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region);
-V1_0::BandConfig BandConfigToHal(JNIEnv *env, jobject jConfig, Region &region);
-
 bool ThrowIfFailed(JNIEnv *env, const hardware::Return<V1_0::Result> &hidlResult);
 bool ThrowIfFailed(JNIEnv *env, const hardware::Return<void> &hidlResult);
 
+JavaRef<jobject> BandConfigFromHal(JNIEnv *env, const V1_0::BandConfig &config, Region region);
+V1_0::BandConfig BandConfigToHal(JNIEnv *env, jobject jConfig, Region &region);
+
+V1_0::Direction DirectionToHal(bool directionDown);
+
+JavaRef<jobject> ProgramInfoFromHal(JNIEnv *env, const V1_1::ProgramInfo &info);
+
 } // namespace convert
 } // namespace radio
 } // namespace server
diff --git a/services/core/jni/com_android_server_radio_types.h b/services/core/jni/com_android_server_radio_types.h
index 8430e05..36f7643 100644
--- a/services/core/jni/com_android_server_radio_types.h
+++ b/services/core/jni/com_android_server_radio_types.h
@@ -27,6 +27,11 @@
  * frameworks/base/core/java/android/hardware/radio/RadioManager.java.
  */
 
+enum class HalRevision : jint {
+    V1_0,
+    V1_1,
+};
+
 // Keep in sync with STATUS_* constants from RadioManager.java.
 enum class Status : jint {
     OK = 0,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c7d6b21..9995a3c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -200,6 +200,8 @@
             "com.android.server.wallpaper.WallpaperManagerService$Lifecycle";
     private static final String AUTO_FILL_MANAGER_SERVICE_CLASS =
             "com.android.server.autofill.AutofillManagerService";
+    private static final String TIME_ZONE_RULES_MANAGER_SERVICE_CLASS =
+            "com.android.server.timezone.RulesManagerService$Lifecycle";
 
     private static final String PERSISTENT_DATA_BLOCK_PROP = "ro.frp.pst";
 
@@ -1221,6 +1223,13 @@
                 traceEnd();
             }
 
+            if (!disableNonCoreServices && context.getResources().getBoolean(
+                        R.bool.config_enableUpdateableTimeZoneRules)) {
+                traceBeginAndSlog("StartTimeZoneRulesManagerService");
+                mSystemServiceManager.startService(TIME_ZONE_RULES_MANAGER_SERVICE_CLASS);
+                Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+            }
+
             traceBeginAndSlog("StartAudioService");
             mSystemServiceManager.startService(AudioService.Lifecycle.class);
             traceEnd();
diff --git a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
index 2e8b068..0cf4994 100644
--- a/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BadgeExtractorTest.java
@@ -69,7 +69,7 @@
         Notification n = builder.build();
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
         return r;
     }
 
diff --git a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 5e8b3d4..d4904f5 100644
--- a/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/notification/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -259,7 +259,7 @@
 
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
         mService.addNotification(r);
         return r;
     }
@@ -769,7 +769,7 @@
 
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 0, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
         mService.addNotification(r);
 
         mService.buzzBeepBlinkLocked(r);
diff --git a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
index 33d2d07..24cb72e 100644
--- a/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/GlobalSortKeyComparatorTest.java
@@ -53,21 +53,21 @@
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
         left.setGlobalSortKey("first");
 
         NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
         right.setGlobalSortKey("second");
 
         NotificationRecord last = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
 
 
         final List<NotificationRecord> expected = new ArrayList<>();
@@ -93,13 +93,13 @@
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
 
         NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
         right.setGlobalSortKey("not null");
 
         final List<NotificationRecord> expected = new ArrayList<>();
@@ -124,14 +124,14 @@
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
         left.setGlobalSortKey("not null");
 
         NotificationRecord right = new NotificationRecord(InstrumentationRegistry.getContext(),
                 new StatusBarNotification(PKG,
                         PKG, 1, "media", UID, UID, n,
                         new UserHandle(UserHandle.myUserId()),
-                        "", 1499), getDefaultChannel(), true);
+                        "", 1499), getDefaultChannel());
 
         final List<NotificationRecord> expected = new ArrayList<>();
         expected.add(left);
diff --git a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
index 7a2dbaf..3dbd803 100644
--- a/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/ImportanceExtractorTest.java
@@ -71,7 +71,7 @@
         Notification n = builder.build();
         StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
                 mPid, n, mUser, null, System.currentTimeMillis());
-        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel, true);
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
         return r;
     }
 
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
index ccd2db0..84945ab 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationComparatorTest.java
@@ -108,7 +108,7 @@
                 .build();
         mRecordMinCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
                 callPkg, 1, "minCall", callUid, callUid, n1,
-                new UserHandle(userId), "", 2000), getDefaultChannel(), false);
+                new UserHandle(userId), "", 2000), getDefaultChannel());
         mRecordMinCall.setUserImportance(NotificationManager.IMPORTANCE_MIN);
 
         Notification n2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -118,7 +118,7 @@
                 .build();
         mRecordHighCall = new NotificationRecord(mContext, new StatusBarNotification(callPkg,
                 callPkg, 1, "highcall", callUid, callUid, n2,
-                new UserHandle(userId), "", 1999), getDefaultChannel(), false);
+                new UserHandle(userId), "", 1999), getDefaultChannel());
         mRecordHighCall.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
 
         Notification n3 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -128,14 +128,14 @@
                 .build();
         mRecordDefaultMedia = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "media", uid2, uid2, n3, new UserHandle(userId),
-                "", 1499), getDefaultChannel(), false);
+                "", 1499), getDefaultChannel());
         mRecordDefaultMedia.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n4 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
                 .setStyle(new Notification.MessagingStyle("sender!")).build();
         mRecordInlineReply = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "inlinereply", uid2, uid2, n4, new UserHandle(userId),
-                "", 1599), getDefaultChannel(), false);
+                "", 1599), getDefaultChannel());
         mRecordInlineReply.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
         mRecordInlineReply.setPackagePriority(Notification.PRIORITY_MAX);
 
@@ -143,27 +143,27 @@
                 .setCategory(Notification.CATEGORY_MESSAGE).build();
         mRecordSms = new NotificationRecord(mContext, new StatusBarNotification(smsPkg,
                 smsPkg, 1, "sms", smsUid, smsUid, n5, new UserHandle(userId),
-                "", 1299), getDefaultChannel(), false);
+                "", 1299), getDefaultChannel());
         mRecordSms.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n6 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
         mRecordStarredContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "starred", uid2, uid2, n6, new UserHandle(userId),
-                "", 1259), getDefaultChannel(), false);
+                "", 1259), getDefaultChannel());
         mRecordStarredContact.setContactAffinity(ValidateNotificationPeople.STARRED_CONTACT);
         mRecordStarredContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n7 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
         mRecordContact = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "contact", uid2, uid2, n7, new UserHandle(userId),
-                "", 1259), getDefaultChannel(), false);
+                "", 1259), getDefaultChannel());
         mRecordContact.setContactAffinity(ValidateNotificationPeople.VALID_CONTACT);
         mRecordContact.setUserImportance(NotificationManager.IMPORTANCE_DEFAULT);
 
         Notification n8 = new Notification.Builder(mContext, TEST_CHANNEL_ID).build();
         mRecordUrgent = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "urgent", uid2, uid2, n8, new UserHandle(userId),
-                "", 1258), getDefaultChannel(), false);
+                "", 1258), getDefaultChannel());
         mRecordUrgent.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
 
         Notification n9 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -173,7 +173,7 @@
                 .build();
         mRecordCheater = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "cheater", uid2, uid2, n9, new UserHandle(userId),
-                "", 9258), getDefaultChannel(), false);
+                "", 9258), getDefaultChannel());
         mRecordCheater.setUserImportance(NotificationManager.IMPORTANCE_LOW);
         mRecordCheater.setPackagePriority(Notification.PRIORITY_MAX);
 
@@ -181,7 +181,7 @@
                 .setStyle(new Notification.InboxStyle().setSummaryText("message!")).build();
         mRecordEmail = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "email", uid2, uid2, n10, new UserHandle(userId),
-                "", 1599), getDefaultChannel(), false);
+                "", 1599), getDefaultChannel());
         mRecordEmail.setUserImportance(NotificationManager.IMPORTANCE_HIGH);
 
         Notification n11 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
@@ -190,7 +190,7 @@
                 .build();
         mRecordCheaterColorized = new NotificationRecord(mContext, new StatusBarNotification(pkg2,
                 pkg2, 1, "cheater", uid2, uid2, n11, new UserHandle(userId),
-                "", 9258), getDefaultChannel(), false);
+                "", 9258), getDefaultChannel());
         mRecordCheaterColorized.setUserImportance(NotificationManager.IMPORTANCE_LOW);
     }
 
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index f3eb4f8..177c02d 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -165,7 +165,7 @@
 
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", uid, 0,
                 nb.build(), new UserHandle(uid), null, 0);
-        return new NotificationRecord(mContext, sbn, channel, true);
+        return new NotificationRecord(mContext, sbn, channel);
     }
     private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
         return generateNotificationRecord(channel, null);
@@ -184,7 +184,7 @@
         }
         StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", uid, 0,
                 nb.build(), new UserHandle(uid), null, 0);
-        return new NotificationRecord(mContext, sbn, channel, true);
+        return new NotificationRecord(mContext, sbn, channel);
     }
 
     @Test
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
index 66f3799..1c8ca84 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationRecordTest.java
@@ -21,6 +21,7 @@
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.when;
 
@@ -60,10 +61,6 @@
     private final Context mMockContext = Mockito.mock(Context.class);
     @Mock PackageManager mPm;
 
-    // constants for targetSdk version. N is pre channels, O is post.
-    private final boolean N = false;
-    private final boolean O = true;
-
     private final String pkg = "com.android.server.notification";
     private final int uid = 9583;
     private final String pkg2 = "pkg2";
@@ -79,6 +76,7 @@
             new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "test",
                     NotificationManager.IMPORTANCE_UNSPECIFIED);
     private android.os.UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
+    final ApplicationInfo legacy = new ApplicationInfo();
     final ApplicationInfo upgrade = new ApplicationInfo();
 
     private static final long[] CUSTOM_VIBRATION = new long[] {
@@ -102,13 +100,17 @@
                 InstrumentationRegistry.getContext().getResources());
         when(mMockContext.getPackageManager()).thenReturn(mPm);
 
+        legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
         upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
-        when(mMockContext.getApplicationInfo()).thenReturn(upgrade);
+        try {
+            when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy);
+            when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade);
+        } catch (PackageManager.NameNotFoundException e) {}
     }
 
-    private StatusBarNotification getNotification(boolean supportsChannels, boolean noisy,
-            boolean defaultSound, boolean buzzy, boolean defaultVibration, boolean lights,
-            boolean defaultLights) {
+    private StatusBarNotification getNotification(boolean preO, boolean noisy, boolean defaultSound,
+            boolean buzzy, boolean defaultVibration, boolean lights, boolean defaultLights) {
+        when(mMockContext.getApplicationInfo()).thenReturn(preO ? legacy : upgrade);
         final Builder builder = new Builder(mMockContext)
                 .setContentTitle("foo")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -147,13 +149,13 @@
         }
 
         builder.setDefaults(defaults);
-        if (supportsChannels) {
+        if (!preO) {
             builder.setChannelId(channelId);
         }
 
 
         Notification n = builder.build();
-        if (!supportsChannels) {
+        if (preO) {
             return new StatusBarNotification(pkg, pkg, id1, tag1, uid, uid, n,
                     mUser, null, uid);
         } else {
@@ -170,11 +172,11 @@
     public void testSound_default_preUpgradeUsesNotification() throws Exception {
         defaultChannel.setSound(null, null);
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, record.getSound());
         assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
     }
@@ -183,11 +185,11 @@
     public void testSound_custom_preUpgradeUsesNotification() throws Exception {
         defaultChannel.setSound(null, null);
         // pre upgrade, custom sound.
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(CUSTOM_SOUND, record.getSound());
         assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
     }
@@ -197,11 +199,11 @@
         defaultChannel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_SOUND);
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(CUSTOM_SOUND, record.getSound());
         assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
     }
@@ -209,11 +211,11 @@
     @Test
     public void testSound_noSound_preUpgrade() throws Exception {
         // pre upgrade, default sound.
-        StatusBarNotification sbn = getNotification(N, false /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
                 false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(null, record.getSound());
         assertEquals(Notification.AUDIO_ATTRIBUTES_DEFAULT, record.getAudioAttributes());
     }
@@ -222,11 +224,11 @@
     public void testSound_default_upgradeUsesChannel() throws Exception {
         channel.setSound(CUSTOM_SOUND, CUSTOM_ATTRIBUTES);
         // post upgrade, default sound.
-        StatusBarNotification sbn = getNotification(O, true /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(CUSTOM_SOUND, record.getSound());
         assertEquals(CUSTOM_ATTRIBUTES, record.getAudioAttributes());
     }
@@ -235,11 +237,11 @@
     public void testVibration_default_preUpgradeUsesNotification() throws Exception {
         defaultChannel.enableVibration(false);
         // pre upgrade, default vibration.
-        StatusBarNotification sbn = getNotification(N, false /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, true /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertNotNull(record.getVibration());
     }
 
@@ -247,11 +249,11 @@
     public void testVibration_custom_preUpgradeUsesNotification() throws Exception {
         defaultChannel.enableVibration(false);
         // pre upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(N, false /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(CUSTOM_VIBRATION, record.getVibration());
     }
 
@@ -260,11 +262,11 @@
         defaultChannel.enableVibration(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION);
         // pre upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(N, false /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertTrue(!Objects.equals(CUSTOM_VIBRATION, record.getVibration()));
     }
 
@@ -272,20 +274,20 @@
     public void testVibration_custom_upgradeUsesChannel() throws Exception {
         channel.enableVibration(true);
         // post upgrade, custom vibration.
-        StatusBarNotification sbn = getNotification(O, false /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
                 false /* defaultSound */, true /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(CUSTOM_CHANNEL_VIBRATION, record.getVibration());
     }
 
     @Test
     public void testImportance_preUpgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
     }
 
@@ -293,11 +295,11 @@
     public void testImportance_locked_preUpgrade() throws Exception {
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(NotificationManager.IMPORTANCE_LOW, record.getImportance());
     }
 
@@ -305,39 +307,39 @@
     public void testImportance_locked_unspecified_preUpgrade() throws Exception {
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_UNSPECIFIED);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE);
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
 
-        NotificationRecord record =  new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(NotificationManager.IMPORTANCE_HIGH, record.getImportance());
     }
 
     @Test
     public void testImportance_upgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(O, true /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(NotificationManager.IMPORTANCE_DEFAULT, record.getImportance());
     }
 
     @Test
     public void testLights_preUpgrade_noLight() throws Exception {
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertNull(record.getLight());
     }
 
 
     @Test
     public void testLights_preUpgrade() throws Exception {
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertEquals(CUSTOM_LIGHT, record.getLight());
     }
 
@@ -345,11 +347,11 @@
     public void testLights_locked_preUpgrade() throws Exception {
         defaultChannel.enableLights(true);
         defaultChannel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS);
-        StatusBarNotification sbn = getNotification(N, true /* noisy */,
+        StatusBarNotification sbn = getNotification(true /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /*defaultLights */);
 
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, N);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertFalse(CUSTOM_LIGHT.equals(record.getLight()));
     }
 
@@ -364,10 +366,10 @@
 
         NotificationRecord.Light expected = new NotificationRecord.Light(
                 defaultLightColor, defaultLightOn, defaultLightOff);
-        StatusBarNotification sbn = getNotification(O, true /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, true /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(expected, record.getLight());
     }
 
@@ -380,19 +382,19 @@
 
         NotificationRecord.Light expected = new NotificationRecord.Light(
                 Color.BLUE, defaultLightOn, defaultLightOff);
-        StatusBarNotification sbn = getNotification(O, true /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 true /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
         assertEquals(expected, record.getLight());
     }
 
     @Test
     public void testLights_upgrade_noLight() throws Exception {
-        StatusBarNotification sbn = getNotification(O, true /* noisy */,
+        StatusBarNotification sbn = getNotification(false /*preO */, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
                 false /* lights */, false /*defaultLights */);
-        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel, O);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel);
         assertNull(record.getLight());
     }
 }
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index e2428b9..7bef033 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -124,7 +124,7 @@
                 .build();
         mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiGroupGSortA, user,
-                null, System.currentTimeMillis()), getDefaultChannel(), false);
+                null, System.currentTimeMillis()), getDefaultChannel());
 
         mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("B")
@@ -134,7 +134,7 @@
                 .build();
         mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiGroupGSortB, user,
-                null, System.currentTimeMillis()), getDefaultChannel(), false);
+                null, System.currentTimeMillis()), getDefaultChannel());
 
         mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("C")
@@ -142,7 +142,7 @@
                 .build();
         mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiNoGroup, user,
-                null, System.currentTimeMillis()), getDefaultChannel(), false);
+                null, System.currentTimeMillis()), getDefaultChannel());
 
         mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("D")
@@ -150,7 +150,7 @@
                 .build();
         mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiNoGroup2, user,
-                null, System.currentTimeMillis()), getDefaultChannel(), false);
+                null, System.currentTimeMillis()), getDefaultChannel());
 
         mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID)
                 .setContentTitle("E")
@@ -159,7 +159,7 @@
                 .build();
         mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification(
                 "package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user,
-                null, System.currentTimeMillis()), getDefaultChannel(), false);
+                null, System.currentTimeMillis()), getDefaultChannel());
 
         mAudioAttributes = new AudioAttributes.Builder()
                 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
@@ -373,7 +373,7 @@
         assertNull(mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
         assertNull(mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
         assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG, UID));
-        assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
+        //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
         assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
     }
 
@@ -696,14 +696,20 @@
         // Returns only non-deleted channels
         List<NotificationChannel> channels =
                 mHelper.getNotificationChannels(PKG, UID, false).getList();
-        assertEquals(1, channels.size());
-        compareChannels(channel2, channels.get(0));
+        assertEquals(2, channels.size());   // Default channel + non-deleted channel
+        for (NotificationChannel nc : channels) {
+            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
+                compareChannels(channel2, nc);
+            }
+        }
 
         // Returns deleted channels too
         channels = mHelper.getNotificationChannels(PKG, UID, true).getList();
-        assertEquals(2, channels.size());
+        assertEquals(3, channels.size());               // Includes default channel
         for (NotificationChannel nc : channels) {
-            compareChannels(channelMap.get(nc.getId()), nc);
+            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
+                compareChannels(channelMap.get(nc.getId()), nc);
+            }
         }
     }
 
@@ -801,8 +807,8 @@
 
         mHelper.permanentlyDeleteNotificationChannels(PKG, UID);
 
-        // No channels remain
-        assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
+        // Only default channel remains
+        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
     }
 
     @Test
@@ -843,6 +849,36 @@
     }
 
     @Test
+    public void testOnUserRemoved() throws Exception {
+        int[] user0Uids = {98, 235, 16, 3782};
+        int[] user1Uids = new int[user0Uids.length];
+        for (int i = 0; i < user0Uids.length; i++) {
+            user1Uids[i] = UserHandle.PER_USER_RANGE + user0Uids[i];
+
+            final ApplicationInfo legacy = new ApplicationInfo();
+            legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+            when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
+
+            // create records with the default channel for all user 0 and user 1 uids
+            mHelper.getImportance(PKG, user0Uids[i]);
+            mHelper.getImportance(PKG, user1Uids[i]);
+        }
+
+        mHelper.onUserRemoved(1);
+
+        // user 0 records remain
+        for (int i = 0; i < user0Uids.length; i++) {
+            assertEquals(1,
+                    mHelper.getNotificationChannels(PKG, user0Uids[i], false).getList().size());
+        }
+        // user 1 records are gone
+        for (int i = 0; i < user1Uids.length; i++) {
+            assertEquals(0,
+                    mHelper.getNotificationChannels(PKG, user1Uids[i], false).getList().size());
+        }
+    }
+
+    @Test
     public void testOnPackageChanged_packageRemoval() throws Exception {
         // Deleted
         NotificationChannel channel1 =
@@ -851,32 +887,13 @@
 
         mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
 
-        // since this is a pre upgrade app, clearing data should restore the default channel
-        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
-        assertEquals(NotificationChannel.DEFAULT_CHANNEL_ID,
-                mHelper.getNotificationChannels(PKG, UID, true).getList().get(0).getId());
+        assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
 
         // Not deleted
         mHelper.createNotificationChannel(PKG, UID, channel1, true);
+
         mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
-        assertEquals(1, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
-    }
-
-    @Test
-    public void testOnPackageChanged_packageRemoval_updatedPackage() throws Exception {
-        // Deleted
-        NotificationChannel channel1 =
-                new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
-        mHelper.createNotificationChannel(UPDATED_PKG, UID2, channel1, true);
-        mHelper.onPackagesChanged(
-                true, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
-        assertEquals(0, mHelper.getNotificationChannels(UPDATED_PKG, UID2, true).getList().size());
-
-        // Not deleted
-        mHelper.createNotificationChannel(UPDATED_PKG, UID2, channel1, true);
-        mHelper.onPackagesChanged(
-                false, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
-        assertEquals(1, mHelper.getNotificationChannels(UPDATED_PKG, UID2, false).getList().size());
+        assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
     }
 
     @Test
@@ -897,23 +914,7 @@
 
         mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
 
-        // default channel restored
-        assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
-        assertNull(mHelper.getNotificationChannelGroups(PKG, UID, true).getList().get(0).getId());
-    }
-
-    @Test
-    public void testOnPackageChanged_packageRemoval_groups_upgraded() throws Exception {
-        NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
-        mHelper.createNotificationChannelGroup(UPDATED_PKG, UID2, ncg, true);
-        NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
-        mHelper.createNotificationChannelGroup(UPDATED_PKG, UID2, ncg2, true);
-
-        mHelper.onPackagesChanged(
-                true, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
-
-        assertEquals(0,
-                mHelper.getNotificationChannelGroups(UPDATED_PKG, UID2, true).getList().size());
+        assertEquals(0, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
     }
 
     @Test
@@ -987,8 +988,9 @@
         assertEquals(3, actual.size());
         for (NotificationChannelGroup group : actual) {
             if (group.getId() == null) {
-                assertEquals(1, group.getChannels().size());
-                assertTrue(channel3.getId().equals(group.getChannels().get(0).getId()));
+                assertEquals(2, group.getChannels().size()); // misc channel too
+                assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
+                        || channel3.getId().equals(group.getChannels().get(1).getId()));
             } else if (group.getId().equals(ncg.getId())) {
                 assertEquals(2, group.getChannels().size());
                 if (group.getChannels().get(0).getId().equals(channel1.getId())) {
@@ -1022,8 +1024,12 @@
         List<NotificationChannelGroup> actual =
                 mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
 
-        assertEquals(1, actual.size());
-        assertEquals(1, actual.get(0).getChannels().size());
+        assertEquals(2, actual.size());
+        for (NotificationChannelGroup group : actual) {
+            if (Objects.equals(group.getId(), ncg.getId())) {
+                assertEquals(1, group.getChannels().size());
+            }
+        }
     }
 
     @Test
diff --git a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
index b1cb4d7..bc25860 100644
--- a/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/SnoozeHelperTest.java
@@ -312,7 +312,7 @@
                 TEST_CHANNEL_ID, "name", NotificationManager.IMPORTANCE_LOW);
         return new NotificationRecord(getContext(), new StatusBarNotification(
                 pkg, pkg, id, tag, 0, 0, n, user, null,
-                System.currentTimeMillis()), notificationChannel, true);
+                System.currentTimeMillis()), notificationChannel);
     }
 
     private NotificationRecord getNotificationRecord(String pkg, int id, String tag,
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index c78488f..bb7e20b 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -368,8 +368,8 @@
     }
 
     @Test
-    public void testSetActiveScorer_noRequestNetworkScoresPermission() {
-        when(mContext.checkCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES))
+    public void testSetActiveScorer_noScoreNetworksPermission() {
+        when(mContext.checkCallingOrSelfPermission(permission.SCORE_NETWORKS))
                 .thenReturn(PackageManager.PERMISSION_DENIED);
 
         try {
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
index 0694eae..ceb92de 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScorerAppManagerTest.java
@@ -228,30 +228,23 @@
     }
 
     @Test
-    public void testSetActiveScorer_nullPackage_validDefault() throws Exception {
-        String packageName = "package";
-        String defaultPackage = "defaultPackage";
-        setNetworkRecoPackageSetting(packageName);
-        setDefaultNetworkRecommendationPackage(defaultPackage);
-        final ComponentName recoComponent = new ComponentName(defaultPackage, "class1");
-        mockScoreNetworksGranted(recoComponent.getPackageName());
-        mockRecommendationServiceAvailable(recoComponent, 924 /* packageUid */, null);
+    public void testSetActiveScorer_nullPackage_currentIsSet() throws Exception {
+        setNetworkRecoPackageSetting("package");
 
         assertTrue(mNetworkScorerAppManager.setActiveScorer(null));
         verify(mSettingsFacade).putString(mMockContext,
-                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, defaultPackage);
+                Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, null);
+        verify(mSettingsFacade).putInt(mMockContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
+                NetworkScoreManager.RECOMMENDATIONS_ENABLED_FORCED_OFF);
     }
 
     @Test
-    public void testSetActiveScorer_nullPackage_invalidDefault() throws Exception {
-        String packageName = "package";
-        String defaultPackage = "defaultPackage";
-        setNetworkRecoPackageSetting(packageName);
-        setDefaultNetworkRecommendationPackage(defaultPackage);
+    public void testSetActiveScorer_nullPackage_currentIsNull() throws Exception {
+        setNetworkRecoPackageSetting(null);
 
-        assertFalse(mNetworkScorerAppManager.setActiveScorer(null));
-        verify(mSettingsFacade, never()).putString(any(),
-                eq(Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE), any());
+        assertTrue(mNetworkScorerAppManager.setActiveScorer(null));
+        verify(mSettingsFacade, never()).putString(any(), any(), any());
     }
 
     @Test
@@ -266,6 +259,9 @@
         assertTrue(mNetworkScorerAppManager.setActiveScorer(newPackage));
         verify(mSettingsFacade).putString(mMockContext,
                 Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE, newPackage);
+        verify(mSettingsFacade).putInt(mMockContext,
+                Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED,
+                NetworkScoreManager.RECOMMENDATIONS_ENABLED_ON);
     }
 
     @Test
@@ -341,6 +337,32 @@
     }
 
     @Test
+    public void testUpdateState_currentPackageNull_defaultNull() throws Exception {
+        setDefaultNetworkRecommendationPackage(null);
+        setNetworkRecoPackageSetting(null);
+
+        mNetworkScorerAppManager.updateState();
+
+        verify(mSettingsFacade, never()).putString(any(),
+                eq(Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE), anyString());
+        verify(mSettingsFacade, never()).putInt(any(),
+                eq(Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED), anyInt());
+    }
+
+    @Test
+    public void testUpdateState_currentPackageEmpty_defaultEmpty() throws Exception {
+        setDefaultNetworkRecommendationPackage("");
+        setNetworkRecoPackageSetting("");
+
+        mNetworkScorerAppManager.updateState();
+
+        verify(mSettingsFacade, never()).putString(any(),
+                eq(Settings.Global.NETWORK_RECOMMENDATIONS_PACKAGE), anyString());
+        verify(mSettingsFacade, never()).putInt(any(),
+                eq(Settings.Global.NETWORK_RECOMMENDATIONS_ENABLED), anyInt());
+    }
+
+    @Test
     public void testUpdateState_currentPackageNotValid_sameAsDefault() throws Exception {
         String defaultPackage = "defaultPackage";
         setDefaultNetworkRecommendationPackage(defaultPackage);
diff --git a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
index 9a9c243..58a4456 100644
--- a/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NightDisplayServiceTest.java
@@ -16,10 +16,12 @@
 
 package com.android.server;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.content.Context;
 import android.content.ContextWrapper;
+import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Secure;
@@ -32,6 +34,7 @@
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.display.DisplayTransformManager;
 import com.android.server.display.NightDisplayService;
+import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
 import org.junit.After;
@@ -41,6 +44,10 @@
 import org.mockito.Mockito;
 
 import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 import static com.google.common.truth.Truth.assertWithMessage;
 import static org.mockito.Mockito.doReturn;
@@ -51,7 +58,7 @@
     private Context mContext;
     private int mUserId;
 
-    private TwilightManager mTwilightManager;
+    private MockTwilightManager mTwilightManager;
 
     private NightDisplayController mNightDisplayController;
     private NightDisplayService mNightDisplayService;
@@ -73,7 +80,7 @@
         final DisplayTransformManager dtm = Mockito.mock(DisplayTransformManager.class);
         LocalServices.addService(DisplayTransformManager.class, dtm);
 
-        mTwilightManager = Mockito.mock(TwilightManager.class);
+        mTwilightManager = new MockTwilightManager();
         LocalServices.addService(TwilightManager.class, mTwilightManager);
 
         mNightDisplayController = new NightDisplayController(mContext, mUserId);
@@ -526,23 +533,371 @@
         assertActivated(true /* activated */);
     }
 
-    /**
-     * Convenience for making a {@link LocalTime} instance with an offset relative to now.
-     *
-     * @param offsetMinutes the offset relative to now (in minutes)
-     * @return the LocalTime instance
-     */
-    private LocalTime getLocalTimeRelativeToNow(int offsetMinutes) {
-        final Calendar c = Calendar.getInstance();
-        c.add(Calendar.MINUTE, offsetMinutes);
-        return new LocalTime(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOffAfterNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOffBeforeNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, -180 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOffDuringNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOffInFuture_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOnAfterNight_turnsOn() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOnBeforeNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -180 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOnDuringNight_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedAfterNight_ifOnInFuture_turnsOff() {
+        setAutoModeTwilight(-120 /* sunsetOffset */, -60 /* sunriseOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOffAfterNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, 180 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOffBeforeNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOffDuringNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOffInPast_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOnAfterNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, 180 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOnBeforeNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOnDuringNight_turnsOff() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedBeforeNight_ifOnInPast_turnsOn() {
+        setAutoModeTwilight(60 /* sunsetOffset */, 120 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOffAfterNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOffBeforeNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOffDuringNightInFuture_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOffDuringNightInPast_turnsOff() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(false /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(false /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(false /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOnAfterNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, 90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOnBeforeNight_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, -90 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOnDuringNightInFuture_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, 30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
+    }
+
+    @Test
+    public void twilightSchedule_whenRebootedDuringNight_ifOnDuringNightInPast_turnsOn() {
+        setAutoModeTwilight(-60 /* sunsetOffset */, 60 /* sunriseOffset */);
+        setActivated(true /* activated */, -30 /* lastActivatedTimeOffset */);
+
+        final TwilightState state = mTwilightManager.getLastTwilightState();
+        mTwilightManager.setTwilightState(null);
+
+        startService();
+        assertActivated(true /* activated */);
+
+        mTwilightManager.setTwilightState(state);
+        assertActivated(true /* activated */);
     }
 
     /**
      * Configures Night display to use a custom schedule.
      *
      * @param startTimeOffset the offset relative to now to activate Night display (in minutes)
-     * @param endTimeOffset   the offset relative to now to deactivate Night display (in minutes)
+     * @param endTimeOffset the offset relative to now to deactivate Night display (in minutes)
      */
     private void setAutoModeCustom(int startTimeOffset, int endTimeOffset) {
         mNightDisplayController.setAutoMode(NightDisplayController.AUTO_MODE_CUSTOM);
@@ -553,34 +908,21 @@
     /**
      * Configures Night display to use the twilight schedule.
      *
-     * @param sunsetOffset  the offset relative to now for sunset (in minutes)
+     * @param sunsetOffset the offset relative to now for sunset (in minutes)
      * @param sunriseOffset the offset relative to now for sunrise (in minutes)
      */
     private void setAutoModeTwilight(int sunsetOffset, int sunriseOffset) {
         mNightDisplayController.setAutoMode(NightDisplayController.AUTO_MODE_TWILIGHT);
-
-        final LocalTime sunset = getLocalTimeRelativeToNow(sunsetOffset);
-        final LocalTime sunrise = getLocalTimeRelativeToNow(sunriseOffset);
-
-        final Calendar now = Calendar.getInstance();
-        long sunsetMillis = sunset.getDateTimeBefore(now).getTimeInMillis();
-        long sunriseMillis = sunrise.getDateTimeBefore(now).getTimeInMillis();
-        if (sunsetMillis < sunriseMillis) {
-            sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis();
-        } else {
-            sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis();
-        }
-
-        final TwilightState state = new TwilightState(sunriseMillis, sunsetMillis);
-        doReturn(state).when(mTwilightManager).getLastTwilightState();
+        mTwilightManager.setTwilightState(
+                getTwilightStateRelativeToNow(sunsetOffset, sunriseOffset));
     }
 
     /**
      * Configures the Night display activated state.
      *
-     * @param activated               {@code true} if Night display should be activated
+     * @param activated {@code true} if Night display should be activated
      * @param lastActivatedTimeOffset the offset relative to now to record that Night display was
-                                      activated (in minutes)
+     * activated (in minutes)
      */
     private void setActivated(boolean activated, int lastActivatedTimeOffset) {
         mNightDisplayController.setActivated(activated);
@@ -617,4 +959,93 @@
                 .that(mNightDisplayController.isActivated())
                 .isEqualTo(activated);
     }
+
+    /**
+     * Convenience for making a {@link LocalTime} instance with an offset relative to now.
+     *
+     * @param offsetMinutes the offset relative to now (in minutes)
+     * @return the LocalTime instance
+     */
+    private static LocalTime getLocalTimeRelativeToNow(int offsetMinutes) {
+        final Calendar c = Calendar.getInstance();
+        c.add(Calendar.MINUTE, offsetMinutes);
+        return new LocalTime(c.get(Calendar.HOUR_OF_DAY), c.get(Calendar.MINUTE));
+    }
+
+    /**
+     * Convenience for making a {@link TwilightState} instance with sunrise/sunset relative to now.
+     *
+     * @param sunsetOffset the offset relative to now for sunset (in minutes)
+     * @param sunriseOffset the offset relative to now for sunrise (in minutes)
+     * @return the TwilightState instance
+     */
+    private static TwilightState getTwilightStateRelativeToNow(int sunsetOffset,
+            int sunriseOffset) {
+        final LocalTime sunset = getLocalTimeRelativeToNow(sunsetOffset);
+        final LocalTime sunrise = getLocalTimeRelativeToNow(sunriseOffset);
+
+        final Calendar now = Calendar.getInstance();
+        long sunsetMillis = sunset.getDateTimeBefore(now).getTimeInMillis();
+        long sunriseMillis = sunrise.getDateTimeBefore(now).getTimeInMillis();
+        if (sunsetMillis < sunriseMillis) {
+            sunsetMillis = sunset.getDateTimeAfter(now).getTimeInMillis();
+        } else {
+            sunriseMillis = sunrise.getDateTimeAfter(now).getTimeInMillis();
+        }
+
+        return new TwilightState(sunriseMillis, sunsetMillis);
+    }
+
+    private static class MockTwilightManager implements TwilightManager {
+
+        private final Map<TwilightListener, Handler> mListeners = new HashMap<>();
+        private TwilightState mTwilightState;
+
+        /**
+         * Updates the TwilightState and notifies any registered listeners.
+         *
+         * @param state the new TwilightState to use
+         */
+        void setTwilightState(TwilightState state) {
+            synchronized (mListeners) {
+                mTwilightState = state;
+
+                final CountDownLatch latch = new CountDownLatch(mListeners.size());
+                for (Map.Entry<TwilightListener, Handler> entry : mListeners.entrySet()) {
+                    entry.getValue().post(new Runnable() {
+                        @Override
+                        public void run() {
+                            entry.getKey().onTwilightStateChanged(state);
+                            latch.countDown();
+                        }
+                    });
+                }
+
+                try {
+                    latch.await(5, TimeUnit.SECONDS);
+                } catch (InterruptedException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+
+        @Override
+        public void registerListener(@NonNull TwilightListener listener, @NonNull Handler handler) {
+            synchronized (mListeners) {
+                mListeners.put(listener, handler);
+            }
+        }
+
+        @Override
+        public void unregisterListener(@NonNull TwilightListener listener) {
+            synchronized (mListeners) {
+                mListeners.remove(listener);
+            }
+        }
+
+        @Override
+        public TwilightState getLastTwilightState() {
+            return mTwilightState;
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
index c87eaed..711c36b 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityStackTests.java
@@ -21,6 +21,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
+import android.app.ActivityManager;
 import android.content.ComponentName;
 import android.content.pm.ActivityInfo;
 import android.platform.test.annotations.Presubmit;
@@ -97,4 +98,25 @@
 
         testStack.stopActivityLocked(activityRecord);
     }
+
+    /**
+     * This test verifies that {@link ActivityStack#STACK_VISIBLE_ACTIVITY_BEHIND} is returned from
+     * {@link ActivityStack#shouldBeVisible(ActivityRecord)} from a fullscreen workspace stack with
+     * a visible behind activity when top focused stack is the home stack.
+     */
+    @Test
+    public void testShouldBeVisibleWithVisibleBehindActivity() throws Exception {
+        final ActivityManagerService service = createActivityManagerService();
+        final TaskRecord task = createTask(service, testActivityComponent,
+                ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID);
+        final ActivityStack fullscreenWorkspaceStackId = task.getStack();
+        final ActivityStack homeStack = service.mStackSupervisor.getStack(
+                ActivityManager.StackId.HOME_STACK_ID, true /*createStaticStackIfNeeded*/,
+                true /*onTop*/);
+        final ActivityRecord activityRecord = createActivity(service, testActivityComponent, task);
+        service.mStackSupervisor.setFocusStackUnchecked("testEmptyStackShouldBeVisible", homeStack);
+        service.mStackSupervisor.requestVisibleBehindLocked(activityRecord, true);
+        assertEquals(ActivityStack.STACK_VISIBLE_ACTIVITY_BEHIND,
+                fullscreenWorkspaceStackId.shouldBeVisible(null /*starting*/));
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
index 28051f9..9cfa542 100644
--- a/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/am/ActivityTestsBase.java
@@ -151,9 +151,12 @@
      * setup not available in the test environment. Also specifies an injector for
      */
     protected static class TestActivityStackSupervisor extends ActivityStackSupervisor {
+        private final ActivityDisplay mDisplay;
+
         public TestActivityStackSupervisor(ActivityManagerService service, Looper looper) {
             super(service, looper);
             mWindowManager = prepareMockWindowManager();
+            mDisplay = new ActivityDisplay();
         }
 
         // No home stack is set.
@@ -185,9 +188,8 @@
 
         public <T extends ActivityStack> T createTestStack(ActivityManagerService service,
                 int stackId, boolean onTop) {
-            final ActivityDisplay display = new ActivityDisplay();
             final TestActivityContainer container =
-                    new TestActivityContainer(service, stackId, display, onTop);
+                    new TestActivityContainer(service, stackId, mDisplay, onTop);
             mActivityContainers.put(stackId, container);
             return (T) container.getStack();
         }
diff --git a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
index 4c53915..27ef9d7 100644
--- a/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/TrampolineTest.java
@@ -56,7 +56,6 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.PrintWriter;
-import java.util.concurrent.LinkedBlockingDeque;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
@@ -600,6 +599,39 @@
     }
 
     @Test
+    public void selectBackupTransportAsync_calledBeforeInitialize_ignored_nullListener()
+            throws Exception {
+        mTrampoline.selectBackupTransportAsync(TRANSPORT_COMPONENT_NAME, null);
+        verifyNoMoreInteractions(mBackupManagerServiceMock);
+        // No crash.
+    }
+
+    @Test
+    public void selectBackupTransportAsync_calledBeforeInitialize_ignored_listenerThrowException()
+            throws Exception {
+        mTrampoline.selectBackupTransportAsync(
+                TRANSPORT_COMPONENT_NAME,
+                new ISelectBackupTransportCallback() {
+                    @Override
+                    public void onSuccess(String transportName) throws RemoteException {
+
+                    }
+
+                    @Override
+                    public void onFailure(int reason) throws RemoteException {
+                        throw new RemoteException("Crash");
+                    }
+
+                    @Override
+                    public IBinder asBinder() {
+                        return null;
+                    }
+                });
+        verifyNoMoreInteractions(mBackupManagerServiceMock);
+        // No crash.
+    }
+
+    @Test
     public void selectBackupTransportAsync_forwarded() throws RemoteException {
         mTrampoline.initialize(UserHandle.USER_SYSTEM);
         mTrampoline.selectBackupTransportAsync(TRANSPORT_COMPONENT_NAME, null);
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
index 267b34f..650681e 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
@@ -19,6 +19,8 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.Signature;
 import android.os.Process;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
@@ -29,6 +31,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Random;
+
 @SmallTest
 @Presubmit
 @RunWith(AndroidJUnit4.class)
@@ -36,8 +40,10 @@
     private static final String CUSTOM_BACKUP_AGENT_NAME = "custom.backup.agent";
     private static final String TEST_PACKAGE_NAME = "test_package";
 
+    private final Random mRandom = new Random(1000000009);
+
     @Test
-    public void appIsEligibleForBackup_backupNotAllowed_returnsFalse() {
+    public void appIsEligibleForBackup_backupNotAllowed_returnsFalse() throws Exception {
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.flags = 0;
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
@@ -50,7 +56,8 @@
     }
 
     @Test
-    public void appIsEligibleForBackup_systemAppWithoutCustomBackupAgent_returnsFalse() {
+    public void appIsEligibleForBackup_systemAppWithoutCustomBackupAgent_returnsFalse()
+            throws Exception {
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
         applicationInfo.uid = Process.SYSTEM_UID;
@@ -63,7 +70,7 @@
     }
 
     @Test
-    public void appIsEligibleForBackup_sharedStorageBackupPackage_returnsFalse() {
+    public void appIsEligibleForBackup_sharedStorageBackupPackage_returnsFalse() throws Exception {
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
         applicationInfo.uid = Process.SYSTEM_UID;
@@ -76,7 +83,8 @@
     }
 
     @Test
-    public void appIsEligibleForBackup_systemAppWithCustomBackupAgent_returnsTrue() {
+    public void appIsEligibleForBackup_systemAppWithCustomBackupAgent_returnsTrue()
+            throws Exception {
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
         applicationInfo.uid = Process.SYSTEM_UID;
@@ -89,7 +97,8 @@
     }
 
     @Test
-    public void appIsEligibleForBackup_nonSystemAppWithoutCustomBackupAgent_returnsTrue() {
+    public void appIsEligibleForBackup_nonSystemAppWithoutCustomBackupAgent_returnsTrue()
+            throws Exception {
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
@@ -102,7 +111,8 @@
     }
 
     @Test
-    public void appIsEligibleForBackup_nonSystemAppWithCustomBackupAgent_returnsTrue() {
+    public void appIsEligibleForBackup_nonSystemAppWithCustomBackupAgent_returnsTrue()
+            throws Exception {
         ApplicationInfo applicationInfo = new ApplicationInfo();
         applicationInfo.flags |= ApplicationInfo.FLAG_ALLOW_BACKUP;
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
@@ -114,4 +124,337 @@
         assertThat(isEligible).isTrue();
     }
 
+    @Test
+    public void appIsStopped_returnsTrue() throws Exception {
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.flags |= ApplicationInfo.FLAG_STOPPED;
+
+        boolean isStopped = AppBackupUtils.appIsStopped(applicationInfo);
+
+        assertThat(isStopped).isTrue();
+    }
+
+    @Test
+    public void appIsStopped_returnsFalse() throws Exception {
+        ApplicationInfo applicationInfo = new ApplicationInfo();
+        applicationInfo.flags = ~ApplicationInfo.FLAG_STOPPED;
+
+        boolean isStopped = AppBackupUtils.appIsStopped(applicationInfo);
+
+        assertThat(isStopped).isFalse();
+    }
+
+    @Test
+    public void appGetsFullBackup_noCustomBackupAgent_returnsTrue() throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.backupAgentName = null;
+
+        boolean result = AppBackupUtils.appGetsFullBackup(packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void appGetsFullBackup_withCustomBackupAgentAndFullBackupOnlyFlag_returnsTrue()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.backupAgentName = "backup.agent";
+        packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
+
+        boolean result = AppBackupUtils.appGetsFullBackup(packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void appGetsFullBackup_withCustomBackupAgentAndWithoutFullBackupOnlyFlag_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.backupAgentName = "backup.agent";
+        packageInfo.applicationInfo.flags = ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
+
+        boolean result = AppBackupUtils.appGetsFullBackup(packageInfo);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void appIsKeyValueOnly_noCustomBackupAgent_returnsTrue() throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.backupAgentName = null;
+
+        boolean result = AppBackupUtils.appIsKeyValueOnly(packageInfo);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void appIsKeyValueOnly_withCustomBackupAgentAndFullBackupOnlyFlag_returnsTrue()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.backupAgentName = "backup.agent";
+        packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
+
+        boolean result = AppBackupUtils.appIsKeyValueOnly(packageInfo);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void appIsKeyValueOnly_withCustomBackupAgentAndWithoutFullBackupOnlyFlag_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.backupAgentName = "backup.agent";
+        packageInfo.applicationInfo.flags = ~ApplicationInfo.FLAG_FULL_BACKUP_ONLY;
+
+        boolean result = AppBackupUtils.appIsKeyValueOnly(packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void signaturesMatch_targetIsNull_returnsFalse() throws Exception {
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], null);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_systemApplication_returnsTrue() throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.applicationInfo = new ApplicationInfo();
+        packageInfo.applicationInfo.flags |= ApplicationInfo.FLAG_SYSTEM;
+
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void signaturesMatch_allowsUnsignedApps_bothSignaturesNull_returnsTrue()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = null;
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(null, packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void signaturesMatch_allowsUnsignedApps_bothSignaturesEmpty_returnsTrue()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = new Signature[0];
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void
+    signaturesMatch_allowsUnsignedApps_storedSignatureNullTargetSignatureEmpty_returnsTrue()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = new Signature[0];
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(null, packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void
+    signaturesMatch_allowsUnsignedApps_storedSignatureEmptyTargetSignatureNull_returnsTrue()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = null;
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void
+    signaturesMatch_disallowsAppsUnsignedOnOnlyOneDevice_storedSignatureIsNull_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = new Signature[]{generateRandomSignature()};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(null, packageInfo);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void
+    signaturesMatch_disallowsAppsUnsignedOnOnlyOneDevice_targetSignatureIsNull_returnsFalse()
+            throws Exception {
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = null;
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[]{generateRandomSignature()},
+                packageInfo);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_signaturesMatch_returnsTrue() throws Exception {
+        Signature signature1 = generateRandomSignature();
+        Signature signature2 = generateRandomSignature();
+        Signature signature3 = generateRandomSignature();
+        assertThat(signature1).isNotEqualTo(signature2);
+        assertThat(signature2).isNotEqualTo(signature3);
+        assertThat(signature1).isNotEqualTo(signature3);
+
+        Signature signature1Copy = new Signature(signature1.toByteArray());
+        Signature signature2Copy = new Signature(signature2.toByteArray());
+        Signature signature3Copy = new Signature(signature3.toByteArray());
+        assertThat(signature1Copy).isEqualTo(signature1);
+        assertThat(signature2Copy).isEqualTo(signature2);
+        assertThat(signature3Copy).isEqualTo(signature3);
+
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = new Signature[]{signature1, signature2, signature3};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(
+                new Signature[]{signature3Copy, signature1Copy, signature2Copy}, packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void signaturesMatch_extraSignatureInTarget_returnsTrue() throws Exception {
+        Signature signature1 = generateRandomSignature();
+        Signature signature2 = generateRandomSignature();
+        Signature signature3 = generateRandomSignature();
+        assertThat(signature1).isNotEqualTo(signature2);
+        assertThat(signature2).isNotEqualTo(signature3);
+        assertThat(signature1).isNotEqualTo(signature3);
+
+        Signature signature1Copy = new Signature(signature1.toByteArray());
+        Signature signature2Copy = new Signature(signature2.toByteArray());
+        assertThat(signature1Copy).isEqualTo(signature1);
+        assertThat(signature2Copy).isEqualTo(signature2);
+
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = new Signature[]{signature1, signature2, signature3};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(
+                new Signature[]{signature2Copy, signature1Copy}, packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void signaturesMatch_extraSignatureInStored_returnsFalse() throws Exception {
+        Signature signature1 = generateRandomSignature();
+        Signature signature2 = generateRandomSignature();
+        Signature signature3 = generateRandomSignature();
+        assertThat(signature1).isNotEqualTo(signature2);
+        assertThat(signature2).isNotEqualTo(signature3);
+        assertThat(signature1).isNotEqualTo(signature3);
+
+        Signature signature1Copy = new Signature(signature1.toByteArray());
+        Signature signature2Copy = new Signature(signature2.toByteArray());
+        assertThat(signature1Copy).isEqualTo(signature1);
+        assertThat(signature2Copy).isEqualTo(signature2);
+
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = new Signature[]{signature1Copy, signature2Copy};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(
+                new Signature[]{signature1, signature2, signature3}, packageInfo);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_emptyStoredSignatures_returnsTrue() throws Exception {
+        Signature signature1 = generateRandomSignature();
+        Signature signature2 = generateRandomSignature();
+        Signature signature3 = generateRandomSignature();
+        assertThat(signature1).isNotEqualTo(signature2);
+        assertThat(signature2).isNotEqualTo(signature3);
+        assertThat(signature1).isNotEqualTo(signature3);
+
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = new Signature[]{signature1, signature2, signature3};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(new Signature[0], packageInfo);
+
+        assertThat(result).isTrue();
+    }
+
+    @Test
+    public void signaturesMatch_emptyTargetSignatures_returnsFalse() throws Exception {
+        Signature signature1 = generateRandomSignature();
+        Signature signature2 = generateRandomSignature();
+        Signature signature3 = generateRandomSignature();
+        assertThat(signature1).isNotEqualTo(signature2);
+        assertThat(signature2).isNotEqualTo(signature3);
+        assertThat(signature1).isNotEqualTo(signature3);
+
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = new Signature[0];
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(
+                new Signature[]{signature1, signature2, signature3}, packageInfo);
+
+        assertThat(result).isFalse();
+    }
+
+    @Test
+    public void signaturesMatch_oneNonMatchingSignature_returnsFalse() throws Exception {
+        Signature signature1 = generateRandomSignature();
+        Signature signature2 = generateRandomSignature();
+        Signature signature3 = generateRandomSignature();
+        Signature signature4 = generateRandomSignature();
+        assertThat(signature1).isNotEqualTo(signature2);
+        assertThat(signature2).isNotEqualTo(signature3);
+        assertThat(signature1).isNotEqualTo(signature3);
+        assertThat(signature1).isNotEqualTo(signature4);
+        assertThat(signature2).isNotEqualTo(signature4);
+        assertThat(signature3).isNotEqualTo(signature4);
+
+        Signature signature1Copy = new Signature(signature1.toByteArray());
+        Signature signature2Copy = new Signature(signature2.toByteArray());
+        assertThat(signature1Copy).isEqualTo(signature1);
+        assertThat(signature2Copy).isEqualTo(signature2);
+
+        PackageInfo packageInfo = new PackageInfo();
+        packageInfo.signatures = new Signature[]{signature1, signature2, signature3};
+        packageInfo.applicationInfo = new ApplicationInfo();
+
+        boolean result = AppBackupUtils.signaturesMatch(
+                new Signature[]{signature1Copy, signature2Copy, signature4}, packageInfo);
+
+        assertThat(result).isFalse();
+    }
+
+    private Signature generateRandomSignature() {
+        byte[] signatureBytes = new byte[256];
+        mRandom.nextBytes(signatureBytes);
+        return new Signature(signatureBytes);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
index d33a035..87c587a 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/BackupManagerMonitorUtilsTest.java
@@ -31,13 +31,20 @@
 import android.content.pm.PackageInfo;
 import android.os.Bundle;
 import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
 public class BackupManagerMonitorUtilsTest {
     @Mock private IBackupManagerMonitor mMonitorMock;
 
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/BackupObserverUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/BackupObserverUtilsTest.java
index 336b11a..ebe6133 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/BackupObserverUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/BackupObserverUtilsTest.java
@@ -22,12 +22,19 @@
 import android.app.backup.BackupProgress;
 import android.app.backup.IBackupObserver;
 import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
 public class BackupObserverUtilsTest {
     private static final String PACKAGE_NAME = "some.package";
 
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/FullBackupRestoreObserverUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/FullBackupRestoreObserverUtilsTest.java
index dced00e..2f56598 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/FullBackupRestoreObserverUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/FullBackupRestoreObserverUtilsTest.java
@@ -23,12 +23,19 @@
 
 import android.app.backup.IFullBackupRestoreObserver;
 import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import org.junit.Before;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
 public class FullBackupRestoreObserverUtilsTest {
     private static final String PACKAGE_NAME = "some.package";
     @Mock
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
index 325d99a..5e4ba7be 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageManagerSettingsTests.java
@@ -31,13 +31,10 @@
 import static org.junit.Assert.fail;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageUserState;
 import android.content.pm.UserInfo;
-import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManagerInternal;
 import android.support.test.InstrumentationRegistry;
@@ -49,26 +46,17 @@
 import android.util.LongSparseArray;
 
 import com.android.internal.os.AtomicFile;
-import com.android.internal.util.FastPrintWriter;
 import com.android.server.LocalServices;
 
-import org.hamcrest.core.IsNot;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Method;
-import java.nio.charset.StandardCharsets;
-import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.PrintStream;
 import java.security.PublicKey;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 
 @RunWith(AndroidJUnit4.class)
@@ -547,7 +535,6 @@
 
     private void verifyUserState(PackageUserState userState, PackageUserState oldUserState,
             boolean userStateChanged, boolean notLaunched, boolean stopped, boolean installed) {
-        assertThat(userState.blockUninstall, is(false));
         assertThat(userState.enabled, is(0));
         assertThat(userState.hidden, is(false));
         assertThat(userState.installed, is(installed));
@@ -783,31 +770,14 @@
 
     @Before
     public void createUserManagerServiceRef() throws ReflectiveOperationException {
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                Constructor<UserManagerService> umsc;
-                try {
-                    // unregister the user manager from the local service
-                    Method removeServiceForTest = LocalServices.class.getDeclaredMethod(
-                            "removeServiceForTest", Class.class);
-                    removeServiceForTest.invoke(null, UserManagerInternal.class);
-
-                    // now create a new user manager [which registers again with the local service]
-                    umsc = UserManagerService.class.getDeclaredConstructor(
-                            Context.class,
-                            PackageManagerService.class,
-                            Object.class,
-                            File.class);
-                    umsc.setAccessible(true);
-                    UserManagerService ums = umsc.newInstance(InstrumentationRegistry.getContext(),
-                            null /*PackageManagerService*/, new Object() /*packagesLock*/,
-                            new File(InstrumentationRegistry.getContext().getFilesDir(), "user"));
-                } catch (SecurityException
-                        | ReflectiveOperationException
-                        | IllegalArgumentException e) {
-                    fail("Could not create user manager service; " + e);
-                }
+        InstrumentationRegistry.getInstrumentation().runOnMainSync((Runnable) () -> {
+            try {
+                // unregister the user manager from the local service
+                LocalServices.removeServiceForTest(UserManagerInternal.class);
+                new UserManagerService(InstrumentationRegistry.getContext());
+            } catch (Exception e) {
+                e.printStackTrace();
+                fail("Could not create user manager service; " + e);
             }
         });
     }
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
index bf05f21..50be8db 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageUserStateTest.java
@@ -49,10 +49,6 @@
         assertThat(testUserState.equals(oldUserState), is(false));
 
         oldUserState = new PackageUserState();
-        oldUserState.blockUninstall = true;
-        assertThat(testUserState.equals(oldUserState), is(false));
-
-        oldUserState = new PackageUserState();
         oldUserState.ceDataInode = 4000L;
         assertThat(testUserState.equals(oldUserState), is(false));
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
index 4c7bf4d..f4944f9 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java
@@ -7399,4 +7399,50 @@
                     "s21", "s22");
         });
     }
+
+    public void testReturnedByServer() {
+        // Package 1 updated, with manifest shortcuts.
+        addManifestShortcutResource(
+                new ComponentName(CALLING_PACKAGE_1, ShortcutActivity.class.getName()),
+                R.xml.shortcut_1);
+        updatePackageVersion(CALLING_PACKAGE_1, 1);
+        mService.mPackageMonitor.onReceive(getTestContext(),
+                genPackageAddIntent(CALLING_PACKAGE_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(mManager.getManifestShortcuts())
+                    .haveIds("ms1")
+                    .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+
+            assertWith(mManager.getDynamicShortcuts())
+                    .haveIds("s1")
+                    .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+        });
+
+        // Pin them.
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1,
+                    list("ms1", "s1"), getCallingUser());
+            assertWith(getShortcutAsLauncher(USER_0))
+                    .haveIds("ms1", "s1")
+                    .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            assertWith(mManager.getPinnedShortcuts())
+                    .haveIds("ms1", "s1")
+                    .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_0, () -> {
+            // This shows a warning log, but should still work.
+            assertTrue(mManager.setDynamicShortcuts(mManager.getDynamicShortcuts()));
+
+            assertWith(mManager.getDynamicShortcuts())
+                    .haveIds("s1")
+                    .forAllShortcuts(si -> assertTrue(si.isReturnedByServer()));
+        });
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
index 3789086..375edf3 100644
--- a/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/storage/DiskStatsLoggingServiceTest.java
@@ -20,16 +20,31 @@
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
-import static org.mockito.Mockito.eq;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import android.app.job.JobService;
-import android.app.job.JobParameters;
+import android.app.job.JobServiceEngine;
+import android.app.usage.ExternalStorageStats;
+import android.app.usage.StorageStatsManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageStats;
+import android.os.BatteryManager;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.os.storage.StorageManager;
+import android.os.storage.VolumeInfo;
+import android.provider.Settings;
 import android.test.AndroidTestCase;
+import android.test.mock.MockContentResolver;
 
+import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.storage.DiskStatsLoggingService.LogRunnable;
 
 import libcore.io.IoUtils;
@@ -46,14 +61,17 @@
 
 import java.io.File;
 import java.io.PrintStream;
+import java.lang.reflect.Field;
 import java.util.ArrayList;
 
 @RunWith(JUnit4.class)
 public class DiskStatsLoggingServiceTest extends AndroidTestCase {
     @Rule public TemporaryFolder mTemporaryFolder;
     @Rule public TemporaryFolder mDownloads;
-    @Rule public TemporaryFolder mRootDirectory;
     @Mock private AppCollector mCollector;
+    @Mock private JobService mJobService;
+    @Mock private StorageStatsManager mSsm;
+    private ExternalStorageStats mStorageStats;
     private File mInputFile;
 
 
@@ -66,8 +84,10 @@
         mInputFile = mTemporaryFolder.newFile();
         mDownloads = new TemporaryFolder();
         mDownloads.create();
-        mRootDirectory = new TemporaryFolder();
-        mRootDirectory.create();
+        mStorageStats = new ExternalStorageStats();
+        when(mSsm.queryExternalStatsForUser(isNull(String.class), any(UserHandle.class)))
+                .thenReturn(mStorageStats);
+        when(mJobService.getSystemService(anyString())).thenReturn(mSsm);
     }
 
     @Test
@@ -75,9 +95,9 @@
         LogRunnable task = new LogRunnable();
         task.setAppCollector(mCollector);
         task.setDownloadsDirectory(mDownloads.getRoot());
-        task.setRootDirectory(mRootDirectory.getRoot());
         task.setLogOutputFile(mInputFile);
         task.setSystemSize(0L);
+        task.setContext(mJobService);
         task.run();
 
         JSONObject json = getJsonOutput();
@@ -99,10 +119,10 @@
     public void testPopulatedLogTask() throws Exception {
         // Write data to directories.
         writeDataToFile(mDownloads.newFile(), "lol");
-        writeDataToFile(mRootDirectory.newFile("test.jpg"), "1234");
-        writeDataToFile(mRootDirectory.newFile("test.mp4"), "12345");
-        writeDataToFile(mRootDirectory.newFile("test.mp3"), "123456");
-        writeDataToFile(mRootDirectory.newFile("test.whatever"), "1234567");
+        mStorageStats.audioBytes = 6L;
+        mStorageStats.imageBytes = 4L;
+        mStorageStats.videoBytes = 5L;
+        mStorageStats.totalBytes = 22L;
 
         // Write apps.
         ArrayList<PackageStats> apps = new ArrayList<>();
@@ -110,15 +130,16 @@
         testApp.dataSize = 5L;
         testApp.cacheSize = 55L;
         testApp.codeSize = 10L;
+        testApp.userHandle = UserHandle.USER_SYSTEM;
         apps.add(testApp);
-        when(mCollector.getPackageStats(anyInt())).thenReturn(apps);
+        when(mCollector.getPackageStats(anyLong())).thenReturn(apps);
 
         LogRunnable task = new LogRunnable();
         task.setAppCollector(mCollector);
         task.setDownloadsDirectory(mDownloads.getRoot());
-        task.setRootDirectory(mRootDirectory.getRoot());
         task.setLogOutputFile(mInputFile);
         task.setSystemSize(10L);
+        task.setContext(mJobService);
         task.run();
 
         JSONObject json = getJsonOutput();
@@ -143,14 +164,57 @@
         LogRunnable task = new LogRunnable();
         task.setAppCollector(mCollector);
         task.setDownloadsDirectory(mDownloads.getRoot());
-        task.setRootDirectory(mRootDirectory.getRoot());
         task.setLogOutputFile(mInputFile);
         task.setSystemSize(10L);
+        task.setContext(mJobService);
         task.run();
 
         // No exception should be thrown.
     }
 
+    @Test
+    public void testDontCrashOnRun() throws Exception {
+        DiskStatsLoggingService service = spy(new DiskStatsLoggingService());
+        BatteryManager batteryManager = mock(BatteryManager.class);
+        when(batteryManager.isCharging()).thenReturn(true);
+        doReturn(batteryManager).when(service).getSystemService(Context.BATTERY_SERVICE);
+        UserManager userManager = mock(UserManager.class);
+        when(userManager.getUsers()).thenReturn(new ArrayList<>());
+        doReturn(userManager).when(service).getSystemService(Context.USER_SERVICE);
+        doReturn(mSsm).when(service).getSystemService(Context.STORAGE_STATS_SERVICE);
+        doReturn(mock(StorageManager.class))
+                .when(service)
+                .getSystemService(Context.STORAGE_SERVICE);
+
+        MockContentResolver cr = new MockContentResolver();
+        cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        doReturn(cr).when(service).getContentResolver();
+
+        PackageManager pm = mock(PackageManager.class);
+        VolumeInfo volumeInfo =
+                new VolumeInfo(VolumeInfo.ID_PRIVATE_INTERNAL, VolumeInfo.TYPE_PRIVATE, null, null);
+        when(pm.getPrimaryStorageCurrentVolume()).thenReturn(volumeInfo);
+        doReturn(pm).when(service).getPackageManager();
+
+        doReturn(0).when(service).getUserId();
+
+        // UGGGGGHHHHHHH! jobFinished is a final method on JobService which crashes when called if
+        // the JobService isn't initialized for real. ServiceTestCase doesn't let us initialize a
+        // service which is built into the framework without crashing, though, so we can't make a
+        // real initialized service.
+        //
+        // And so, we use reflection to set the JobServiceEngine, which is used by the final method,
+        // to be something which won't crash when called.
+        final Field field = JobService.class.getDeclaredField("mEngine");
+        field.setAccessible(true);
+        field.set(service, mock(JobServiceEngine.class));
+
+        // Note: This won't clobber your on-device cache file because, technically,
+        // FrameworkServicesTests don't have write permission to actually overwrite the cache file.
+        // We log and fail on the write silently in this case.
+        service.onStartJob(null);
+    }
+
     private void writeDataToFile(File f, String data) throws Exception{
         PrintStream out = new PrintStream(f);
         out.print(data);
diff --git a/services/tests/servicestests/src/com/android/server/timezone/CheckTokenTest.java b/services/tests/servicestests/src/com/android/server/timezone/CheckTokenTest.java
new file mode 100644
index 0000000..9603a06
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezone/CheckTokenTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.server.timezone;
+
+import org.junit.Test;
+
+import android.support.test.filters.SmallTest;
+
+import java.io.IOException;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+@SmallTest
+public class CheckTokenTest {
+
+    @Test
+    public void toByteArray() throws Exception {
+        PackageVersions packageVersions =
+                new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
+        CheckToken originalToken = new CheckToken(1 /* optimisticLockId */, packageVersions);
+        assertEquals(originalToken, CheckToken.fromByteArray(originalToken.toByteArray()));
+    }
+
+    @Test
+    public void fromByteArray() {
+        PackageVersions packageVersions =
+                new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
+        CheckToken token = new CheckToken(1, packageVersions);
+        byte[] validTokenBytes = token.toByteArray();
+        byte[] shortTokenBytes = new byte[validTokenBytes.length - 1];
+        System.arraycopy(validTokenBytes, 0, shortTokenBytes, 0, shortTokenBytes.length);
+
+        try {
+            CheckToken.fromByteArray(shortTokenBytes);
+            fail();
+        } catch (IOException expected) {}
+    }
+
+    @Test
+    public void equals() {
+        PackageVersions packageVersions1 =
+                new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
+        PackageVersions packageVersions2 =
+                new PackageVersions(2 /* updateAppVersion */, 2 /* dataAppVersion */);
+        assertFalse(packageVersions1.equals(packageVersions2));
+
+        CheckToken baseline = new CheckToken(1, packageVersions1);
+        assertEquals(baseline, baseline);
+
+        CheckToken deepEqual = new CheckToken(1, packageVersions1);
+        assertEquals(baseline, deepEqual);
+
+        CheckToken differentOptimisticLockId = new CheckToken(2, packageVersions1);
+        assertFalse(differentOptimisticLockId.equals(baseline));
+
+        CheckToken differentPackageVersions = new CheckToken(1, packageVersions2);
+        assertFalse(differentPackageVersions.equals(baseline));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java
new file mode 100644
index 0000000..e085270
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageStatusStorageTest.java
@@ -0,0 +1,229 @@
+/*
+ * 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.server.timezone;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import static junit.framework.Assert.assertTrue;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
+@SmallTest
+public class PackageStatusStorageTest {
+    private static final PackageVersions VALID_PACKAGE_VERSIONS = new PackageVersions(1, 2);
+
+    private PackageStatusStorage mPackageStatusStorage;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getContext();
+
+        // Using the instrumentation context means the database is created in a test app-specific
+        // directory.
+        mPackageStatusStorage = new PackageStatusStorage(context);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mPackageStatusStorage.deleteDatabaseForTests();
+    }
+
+    @Test
+    public void getPackageStatus_initialState() {
+        assertNull(mPackageStatusStorage.getPackageStatus());
+    }
+
+    @Test
+    public void resetCheckState() {
+        // Assert initial state.
+        assertNull(mPackageStatusStorage.getPackageStatus());
+
+        CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
+
+        // There should now be a state.
+        assertNotNull(mPackageStatusStorage.getPackageStatus());
+
+        // Now clear the state.
+        mPackageStatusStorage.resetCheckState();
+
+        // After reset, there should be no package state again.
+        assertNull(mPackageStatusStorage.getPackageStatus());
+
+        CheckToken token2 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
+
+        // Token after a reset should still be distinct.
+        assertFalse(token1.equals(token2));
+
+        // Now clear the state again.
+        mPackageStatusStorage.resetCheckState();
+
+        // After reset, there should be no package state again.
+        assertNull(mPackageStatusStorage.getPackageStatus());
+
+        CheckToken token3 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
+
+        // A CheckToken generated after a reset should still be distinct.
+        assertFalse(token2.equals(token3));
+    }
+
+    @Test
+    public void generateCheckToken_missingRowBehavior() {
+        // Assert initial state.
+        assertNull(mPackageStatusStorage.getPackageStatus());
+
+        CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
+        assertNotNull(token1);
+
+        // There should now be state.
+        assertNotNull(mPackageStatusStorage.getPackageStatus());
+
+        // Corrupt the table by removing the one row.
+        mPackageStatusStorage.deleteRowForTests();
+
+        // Check that generateCheckToken recovers.
+        assertNotNull(mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS));
+    }
+
+    @Test
+    public void getPackageStatus_missingRowBehavior() {
+        // Assert initial state.
+        assertNull(mPackageStatusStorage.getPackageStatus());
+
+        CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
+        assertNotNull(token1);
+
+        // There should now be a state.
+        assertNotNull(mPackageStatusStorage.getPackageStatus());
+
+        // Corrupt the table by removing the one row.
+        mPackageStatusStorage.deleteRowForTests();
+
+        assertNull(mPackageStatusStorage.getPackageStatus());
+    }
+
+    @Test
+    public void markChecked_missingRowBehavior() {
+        // Assert initial state.
+        CheckToken token1 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
+        assertNotNull(token1);
+
+        // There should now be a state.
+        assertNotNull(mPackageStatusStorage.getPackageStatus());
+
+        // Corrupt the table by removing the one row.
+        mPackageStatusStorage.deleteRowForTests();
+
+        // The missing row should mean token1 is now considered invalid, so we should get a false.
+        assertFalse(mPackageStatusStorage.markChecked(token1, true /* succeeded */));
+
+        // The storage should have recovered and we should be able to carry on like before.
+        CheckToken token2 = mPackageStatusStorage.generateCheckToken(VALID_PACKAGE_VERSIONS);
+        assertTrue(mPackageStatusStorage.markChecked(token2, true /* succeeded */));
+    }
+
+    @Test
+    public void checkToken_tokenIsUnique() {
+        PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
+        PackageStatus expectedPackageStatus =
+                new PackageStatus(PackageStatus.CHECK_STARTED, packageVersions);
+
+        CheckToken token1 = mPackageStatusStorage.generateCheckToken(packageVersions);
+        assertEquals(packageVersions, token1.mPackageVersions);
+
+        PackageStatus actualPackageStatus1 = mPackageStatusStorage.getPackageStatus();
+        assertEquals(expectedPackageStatus, actualPackageStatus1);
+
+        CheckToken token2 = mPackageStatusStorage.generateCheckToken(packageVersions);
+        assertEquals(packageVersions, token1.mPackageVersions);
+        assertFalse(token1.mOptimisticLockId == token2.mOptimisticLockId);
+        assertFalse(token1.equals(token2));
+    }
+
+    @Test
+    public void markChecked_checkSucceeded() {
+        PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
+
+        CheckToken token = mPackageStatusStorage.generateCheckToken(packageVersions);
+        boolean writeOk = mPackageStatusStorage.markChecked(token, true /* succeeded */);
+        assertTrue(writeOk);
+
+        PackageStatus expectedPackageStatus =
+                new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
+        assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
+    }
+
+    @Test
+    public void markChecked_checkFailed() {
+        PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
+
+        CheckToken token = mPackageStatusStorage.generateCheckToken(packageVersions);
+        boolean writeOk = mPackageStatusStorage.markChecked(token, false /* succeeded */);
+        assertTrue(writeOk);
+
+        PackageStatus expectedPackageStatus =
+                new PackageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, packageVersions);
+        assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
+    }
+
+    @Test
+    public void markChecked_optimisticLocking_multipleToken() {
+        PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
+        CheckToken token1 = mPackageStatusStorage.generateCheckToken(packageVersions);
+        CheckToken token2 = mPackageStatusStorage.generateCheckToken(packageVersions);
+
+        PackageStatus packageStatusBeforeChecked = mPackageStatusStorage.getPackageStatus();
+
+        boolean writeOk1 = mPackageStatusStorage.markChecked(token1, true /* succeeded */);
+        // Generation of token2 should mean that token1 is no longer valid.
+        assertFalse(writeOk1);
+        assertEquals(packageStatusBeforeChecked, mPackageStatusStorage.getPackageStatus());
+
+        boolean writeOk2 = mPackageStatusStorage.markChecked(token2, true /* succeeded */);
+        // token2 should still be valid, and the attempt with token1 should have had no effect.
+        assertTrue(writeOk2);
+        PackageStatus expectedPackageStatus =
+                new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
+        assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
+    }
+
+    @Test
+    public void markChecked_optimisticLocking_repeatedTokenUse() {
+        PackageVersions packageVersions = VALID_PACKAGE_VERSIONS;
+        CheckToken token = mPackageStatusStorage.generateCheckToken(packageVersions);
+
+        boolean writeOk1 = mPackageStatusStorage.markChecked(token, true /* succeeded */);
+        assertTrue(writeOk1);
+
+        PackageStatus expectedPackageStatus =
+                new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
+        assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
+
+        // token cannot be reused.
+        boolean writeOk2 = mPackageStatusStorage.markChecked(token, true /* succeeded */);
+        assertFalse(writeOk2);
+        assertEquals(expectedPackageStatus, mPackageStatusStorage.getPackageStatus());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageStatusTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageStatusTest.java
new file mode 100644
index 0000000..c0ae81e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageStatusTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.server.timezone;
+
+import org.junit.Test;
+
+import android.support.test.filters.SmallTest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+@SmallTest
+public class PackageStatusTest {
+
+    @Test
+    public void equals() {
+        PackageVersions packageVersions1 =
+                new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
+        PackageVersions packageVersions2 =
+                new PackageVersions(2 /* updateAppVersion */, 1 /* dataAppVersion */);
+        assertFalse(packageVersions1.equals(packageVersions2));
+
+        PackageStatus baseline =
+                new PackageStatus(PackageStatus.CHECK_STARTED, packageVersions1);
+        assertEquals(baseline, baseline);
+
+        PackageStatus deepEqual =
+                new PackageStatus(PackageStatus.CHECK_STARTED, packageVersions1);
+        assertEquals(baseline, deepEqual);
+
+        PackageStatus differentStatus =
+                new PackageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions1);
+        assertFalse(differentStatus.equals(baseline));
+
+        PackageStatus differentPackageVersions =
+                new PackageStatus(PackageStatus.CHECK_STARTED, packageVersions2);
+        assertFalse(differentPackageVersions.equals(baseline));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
new file mode 100644
index 0000000..45b0af3
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageTrackerTest.java
@@ -0,0 +1,1471 @@
+/*
+ * 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.server.timezone;
+
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import android.app.timezone.RulesUpdaterContract;
+import android.content.Context;
+import android.content.Intent;
+import android.provider.TimeZoneRulesDataContract;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.mockito.hamcrest.MockitoHamcrest.argThat;
+
+/**
+ * White box interaction / unit testing of the {@link PackageTracker}.
+ */
+@SmallTest
+public class PackageTrackerTest {
+    private static final String UPDATE_APP_PACKAGE_NAME = "updateAppPackageName";
+    private static final String DATA_APP_PACKAGE_NAME = "dataAppPackageName";
+    private static final PackageVersions INITIAL_APP_PACKAGE_VERSIONS =
+            new PackageVersions(2 /* updateAppVersion */, 2 /* dataAppVersion */);
+
+    private ConfigHelper mMockConfigHelper;
+    private PackageManagerHelper mMockPackageManagerHelper;
+
+    private FakeClockHelper mFakeClock;
+    private FakeIntentHelper mFakeIntentHelper;
+    private PackageStatusStorage mPackageStatusStorage;
+    private PackageTracker mPackageTracker;
+
+    @Before
+    public void setUp() throws Exception {
+        Context context = InstrumentationRegistry.getContext();
+
+        mFakeClock = new FakeClockHelper();
+
+        // Read-only interfaces so are easy to mock.
+        mMockConfigHelper = mock(ConfigHelper.class);
+        mMockPackageManagerHelper = mock(PackageManagerHelper.class);
+
+        // Using the instrumentation context means the database is created in a test app-specific
+        // directory. We can use the real thing for this test.
+        mPackageStatusStorage = new PackageStatusStorage(context);
+
+        // For other interactions with the Android framework we create a fake object.
+        mFakeIntentHelper = new FakeIntentHelper();
+
+        // Create the PackageTracker to use in tests.
+        mPackageTracker = new PackageTracker(
+                mFakeClock,
+                mMockConfigHelper,
+                mMockPackageManagerHelper,
+                mPackageStatusStorage,
+                mFakeIntentHelper);
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        if (mPackageStatusStorage != null) {
+            mPackageStatusStorage.deleteDatabaseForTests();
+        }
+    }
+
+    @Test
+    public void trackingDisabled_intentHelperNotUsed() {
+        // Set up device configuration.
+        configureTrackingDisabled();
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check the IntentHelper was not initialized.
+        mFakeIntentHelper.assertNotInitialized();
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+    }
+
+    @Test
+    public void trackingDisabled_triggerUpdateIfNeededNotAllowed() {
+        // Set up device configuration.
+        configureTrackingDisabled();
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+
+        try {
+            // This call should also not be allowed and will throw an exception if tracking is
+            // disabled.
+            mPackageTracker.triggerUpdateIfNeeded(true);
+            fail();
+        } catch (IllegalStateException expected) {}
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+    }
+
+    @Test
+    public void trackingDisabled_unsolicitedResultsIgnored_withoutToken() {
+        // Set up device configuration.
+        configureTrackingDisabled();
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+
+        // Receiving a check result when tracking is disabled should cause the storage to be
+        // reset.
+        mPackageTracker.recordCheckResult(null /* checkToken */, true /* success */);
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+
+        // Assert the storage was reset.
+        checkPackageStorageStatusIsInitialOrReset();
+    }
+
+    @Test
+    public void trackingDisabled_unsolicitedResultsIgnored_withToken() {
+        // Set up device configuration.
+        configureTrackingDisabled();
+
+        // Set the storage into an arbitrary state so we can detect a reset.
+        mPackageStatusStorage.generateCheckToken(INITIAL_APP_PACKAGE_VERSIONS);
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+
+        // Receiving a check result when tracking is disabled should cause the storage to be reset.
+        mPackageTracker.recordCheckResult(createArbitraryCheckToken(), true /* success */);
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+
+        // Assert the storage was reset.
+        checkPackageStorageStatusIsInitialOrReset();
+    }
+
+    @Test
+    public void trackingEnabled_updateAppConfigMissing() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureUpdateAppPackageNameMissing();
+        configureDataAppPackageOk(DATA_APP_PACKAGE_NAME);
+
+        try {
+            // Initialize the tracker.
+            mPackageTracker.start();
+            fail();
+        } catch (RuntimeException expected) {}
+
+        mFakeIntentHelper.assertNotInitialized();
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+    }
+
+    // TODO(nfuller): Uncomment or delete when it's clear what will happen with http://b/35995024
+    // @Test
+    // public void trackingEnabled_updateAppNotPrivileged() throws Exception {
+    //     // Set up device configuration.
+    //     configureTrackingEnabled();
+    //     configureReliabilityConfigSettingsOk();
+    //     configureUpdateAppPackageNotPrivileged(UPDATE_APP_PACKAGE_NAME);
+    //     configureDataAppPackageOk(DATA_APP_PACKAGE_NAME);
+    //
+    //     try {
+    //         // Initialize the tracker.
+    //         mPackageTracker.start();
+    //         fail();
+    //     } catch (RuntimeException expected) {}
+    //
+    //     mFakeIntentHelper.assertNotInitialized();
+    //
+    //     // Check reliability triggering state.
+    //     mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+    // }
+
+    @Test
+    public void trackingEnabled_dataAppConfigMissing() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureUpdateAppPackageOk(UPDATE_APP_PACKAGE_NAME);
+        configureDataAppPackageNameMissing();
+
+        try {
+            // Initialize the tracker.
+            mPackageTracker.start();
+            fail();
+        } catch (RuntimeException expected) {}
+
+        mFakeIntentHelper.assertNotInitialized();
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+    }
+
+    // TODO(nfuller): Uncomment or delete when it's clear what will happen with http://b/35995024
+    // @Test
+    // public void trackingEnabled_dataAppNotPrivileged() throws Exception {
+    //     // Set up device configuration.
+    //     configureTrackingEnabled();
+    //     configureReliabilityConfigSettingsOk();
+    //     configureUpdateAppPackageOk(UPDATE_APP_PACKAGE_NAME);
+    //     configureDataAppPackageNotPrivileged(DATA_APP_PACKAGE_NAME);
+    //
+    //     try {
+    //         // Initialize the tracker.
+    //         mPackageTracker.start();
+    //         fail();
+    //     } catch (RuntimeException expected) {}
+    //
+    //     mFakeIntentHelper.assertNotInitialized();
+    //
+    //     // Check reliability triggering state.
+    //     mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+    // }
+
+    @Test
+    public void trackingEnabled_packageUpdate_badUpdateAppManifestEntry() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureValidApplications();
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Configure a bad manifest for the update app. Should effectively turn off tracking.
+        PackageVersions packageVersions =
+                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
+        configureUpdateAppManifestBad(UPDATE_APP_PACKAGE_NAME);
+        configureDataAppManifestOk(DATA_APP_PACKAGE_NAME);
+        configureUpdateAppPackageVersion(
+                UPDATE_APP_PACKAGE_NAME, packageVersions.mUpdateAppVersion);
+        configureDataAppPackageVersion(DATA_APP_PACKAGE_NAME, packageVersions.mDataAppVersion);
+        // Simulate a tracked package being updated.
+        mFakeIntentHelper.simulatePackageUpdatedEvent();
+
+        // Assert the PackageTracker did not attempt to trigger an update.
+        mFakeIntentHelper.assertUpdateNotTriggered();
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+
+        // Assert the storage was not touched.
+        checkPackageStorageStatusIsInitialOrReset();
+    }
+
+    @Test
+    public void trackingEnabled_packageUpdate_badDataAppManifestEntry() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureValidApplications();
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Configure a bad manifest for the data app. Should effectively turn off tracking.
+        PackageVersions packageVersions =
+                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
+        configureUpdateAppManifestOk(UPDATE_APP_PACKAGE_NAME);
+        configureDataAppManifestBad(DATA_APP_PACKAGE_NAME);
+        configureUpdateAppPackageVersion(
+                UPDATE_APP_PACKAGE_NAME, packageVersions.mUpdateAppVersion);
+        configureDataAppPackageVersion(DATA_APP_PACKAGE_NAME, packageVersions.mDataAppVersion);
+        mFakeIntentHelper.simulatePackageUpdatedEvent();
+
+        // Assert the PackageTracker did not attempt to trigger an update.
+        mFakeIntentHelper.assertUpdateNotTriggered();
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+
+        // Assert the storage was not touched.
+        checkPackageStorageStatusIsInitialOrReset();
+    }
+
+    @Test
+    public void trackingEnabled_packageUpdate_responseWithToken_success() throws Exception {
+        trackingEnabled_packageUpdate_responseWithToken(true);
+    }
+
+    @Test
+    public void trackingEnabled_packageUpdate_responseWithToken_failed() throws Exception {
+        trackingEnabled_packageUpdate_responseWithToken(false);
+    }
+
+    private void trackingEnabled_packageUpdate_responseWithToken(boolean success) throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureValidApplications();
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Simulate a tracked package being updated.
+        PackageVersions packageVersions =
+                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
+        simulatePackageInstallation(packageVersions);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions);
+
+        // Get the token that was passed to the intent helper, and pass it back.
+        CheckToken token = mFakeIntentHelper.captureAndResetLastToken();
+        mPackageTracker.recordCheckResult(token, success);
+
+        // Check storage and reliability triggering state.
+        if (success) {
+            checkUpdateCheckSuccessful(packageVersions);
+        } else {
+            checkUpdateCheckFailed(packageVersions);
+        }
+    }
+
+    @Test
+    public void trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset_success()
+            throws Exception {
+        trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset(true);
+    }
+
+    @Test
+    public void trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset_failed()
+            throws Exception {
+        trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset(false);
+    }
+
+    private void trackingEnabled_packageUpdate_responseWithoutTokenCausesStorageReset(
+            boolean success) throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureValidApplications();
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Set up installed app versions / manifests.
+        PackageVersions packageVersions =
+                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
+        simulatePackageInstallation(packageVersions);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions);
+
+        // Ignore the token that was given to the intent helper, just pass null.
+        mPackageTracker.recordCheckResult(null /* checkToken */, success);
+
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+
+        // Assert the storage was reset.
+        checkPackageStorageStatusIsInitialOrReset();
+    }
+
+    /**
+     * Two package updates triggered for the same package versions. The second is triggered while
+     * the first is still happening.
+     */
+    @Test
+    public void trackingEnabled_packageUpdate_twoChecksNoPackageChange_secondWhileFirstInProgress()
+            throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureValidApplications();
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Simulate package installation.
+        PackageVersions packageVersions =
+                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
+        simulatePackageInstallation(packageVersions);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions);
+
+        // Get the first token.
+        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
+        assertEquals(packageVersions, token1.mPackageVersions);
+
+        // Now attempt to generate another check while the first is in progress and without having
+        // updated the package versions. The PackageTracker should trigger again for safety.
+        simulatePackageInstallation(packageVersions);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions);
+
+        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
+        assertEquals(packageVersions, token2.mPackageVersions);
+        assertEquals(token1.mPackageVersions, token2.mPackageVersions);
+        assertTrue(token1.mOptimisticLockId != token2.mOptimisticLockId);
+    }
+
+    /**
+     * Two package updates triggered for the same package versions. The second happens after
+     * the first has succeeded.
+     */
+    @Test
+    public void trackingEnabled_packageUpdate_twoChecksNoPackageChange_sequential()
+            throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureValidApplications();
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Simulate package installation.
+        PackageVersions packageVersions =
+                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
+        simulatePackageInstallation(packageVersions);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions);
+
+        // Get the token.
+        CheckToken token = mFakeIntentHelper.captureAndResetLastToken();
+        assertEquals(packageVersions, token.mPackageVersions);
+
+        // Simulate a successful check.
+        mPackageTracker.recordCheckResult(token, true /* success */);
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckSuccessful(packageVersions);
+
+        // Now attempt to generate another check, but without having updated the package. The
+        // PackageTracker should be smart enough to recognize there's nothing to do here.
+        simulatePackageInstallation(packageVersions);
+
+        // Assert the PackageTracker did not attempt to trigger an update.
+        mFakeIntentHelper.assertUpdateNotTriggered();
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckSuccessful(packageVersions);
+    }
+
+    /**
+     * Two package updates triggered for the same package versions. The second is triggered after
+     * the first has failed.
+     */
+    @Test
+    public void trackingEnabled_packageUpdate_afterFailure() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureValidApplications();
+
+        // Initialize the tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Simulate package installation.
+        PackageVersions packageVersions =
+                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
+        simulatePackageInstallation(packageVersions);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions);
+
+        // Get the first token.
+        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
+        assertEquals(packageVersions, token1.mPackageVersions);
+
+        // Simulate an *unsuccessful* check.
+        mPackageTracker.recordCheckResult(token1, false /* success */);
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckFailed(packageVersions);
+
+        // Now generate another check, but without having updated the package. The
+        // PackageTracker should recognize the last check failed and trigger again.
+        simulatePackageInstallation(packageVersions);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions);
+
+        // Get the second token.
+        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
+
+        // Assert some things about the tokens.
+        assertEquals(packageVersions, token2.mPackageVersions);
+        assertTrue(token1.mOptimisticLockId != token2.mOptimisticLockId);
+
+        // For completeness, now simulate this check was successful.
+        mPackageTracker.recordCheckResult(token2, true /* success */);
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckSuccessful(packageVersions);
+    }
+
+    /**
+     * Two package updates triggered for different package versions. The second is triggered while
+     * the first is still happening.
+     */
+    @Test
+    public void trackingEnabled_packageUpdate_twoChecksWithPackageChange_firstCheckInProcess()
+            throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureValidApplications();
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Simulate package installation.
+        PackageVersions packageVersions1 =
+                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
+        simulatePackageInstallation(packageVersions1);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions1);
+
+        // Get the first token.
+        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
+        assertEquals(packageVersions1, token1.mPackageVersions);
+
+        // Simulate a tracked package being updated a second time (before the response for the
+        // first has been received).
+        PackageVersions packageVersions2 =
+                new PackageVersions(3 /* updateAppPackageVersion */, 4 /* dataAppPackageVersion */);
+        simulatePackageInstallation(packageVersions2);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions2);
+
+        // Get the second token.
+        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
+        assertEquals(packageVersions2, token2.mPackageVersions);
+
+        // token1 should be invalid because the token2 was generated.
+        mPackageTracker.recordCheckResult(token1, true /* success */);
+
+        // Reliability triggering should still be enabled.
+        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+
+        // Check the expected storage state.
+        checkPackageStorageStatus(PackageStatus.CHECK_STARTED, packageVersions2);
+
+        // token2 should still be accepted.
+        mPackageTracker.recordCheckResult(token2, true /* success */);
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckSuccessful(packageVersions2);
+    }
+
+    /**
+     * Two package updates triggered for different package versions. The second is triggered after
+     * the first has completed successfully.
+     */
+    @Test
+    public void trackingEnabled_packageUpdate_twoChecksWithPackageChange_sequential()
+            throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureValidApplications();
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Simulate package installation.
+        PackageVersions packageVersions1 =
+                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
+        simulatePackageInstallation(packageVersions1);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions1);
+
+        // Get the first token.
+        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
+        assertEquals(packageVersions1, token1.mPackageVersions);
+
+        // token1 should be accepted.
+        mPackageTracker.recordCheckResult(token1, true /* success */);
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckSuccessful(packageVersions1);
+
+        // Simulate a tracked package being updated a second time.
+        PackageVersions packageVersions2 =
+                new PackageVersions(3 /* updateAppPackageVersion */, 4 /* dataAppPackageVersion */);
+        simulatePackageInstallation(packageVersions2);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions2);
+
+        // Get the second token.
+        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
+        assertEquals(packageVersions2, token2.mPackageVersions);
+
+        // token2 should still be accepted.
+        mPackageTracker.recordCheckResult(token2, true /* success */);
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckSuccessful(packageVersions2);
+    }
+
+    /**
+     * Replaying the same token twice.
+     */
+    @Test
+    public void trackingEnabled_packageUpdate_sameTokenReplayFails() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        configureValidApplications();
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Simulate package installation.
+        PackageVersions packageVersions1 =
+                new PackageVersions(2 /* updateAppPackageVersion */, 3 /* dataAppPackageVersion */);
+        simulatePackageInstallation(packageVersions1);
+
+        // Confirm an update was triggered.
+        checkUpdateCheckTriggered(packageVersions1);
+
+        // Get the first token.
+        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
+        assertEquals(packageVersions1, token1.mPackageVersions);
+
+        // token1 should be accepted.
+        mPackageTracker.recordCheckResult(token1, true /* success */);
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckSuccessful(packageVersions1);
+
+        // Apply token1 again.
+        mPackageTracker.recordCheckResult(token1, true /* success */);
+
+        // Check the expected storage state. No real way to tell if it has been updated, but
+        // we can check the final state is still what it should be.
+        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions1);
+
+        // Under the covers we expect it to fail to update because the storage should recognize that
+        // the token is no longer valid.
+        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+
+        // Peek inside the package tracker to make sure it is tracking failure counts properly.
+        assertEquals(1, mPackageTracker.getCheckFailureCountForTests());
+    }
+
+    @Test
+    public void trackingEnabled_reliabilityTrigger_firstTime_initialStorage() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        PackageVersions packageVersions = configureValidApplications();
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatusIsInitialOrReset();
+
+        // Simulate a reliability trigger.
+        mFakeIntentHelper.simulateReliabilityTrigger();
+
+        // Assert the PackageTracker did trigger an update.
+        checkUpdateCheckTriggered(packageVersions);
+
+        // Confirm the token was correct.
+        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
+        assertEquals(packageVersions, token1.mPackageVersions);
+
+        // token1 should be accepted.
+        mPackageTracker.recordCheckResult(token1, true /* success */);
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckSuccessful(packageVersions);
+    }
+
+    @Test
+    public void trackingEnabled_reliabilityTrigger_afterRebootNoTriggerNeeded() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+        PackageVersions packageVersions = configureValidApplications();
+
+        // Force the storage into a state we want.
+        mPackageStatusStorage.forceCheckStateForTests(
+                PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
+
+        // Simulate a reliability trigger.
+        mFakeIntentHelper.simulateReliabilityTrigger();
+
+        // Assert the PackageTracker did not attempt to trigger an update.
+        mFakeIntentHelper.assertUpdateNotTriggered();
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckSuccessful(packageVersions);
+    }
+
+    /**
+     * Simulates the device starting where the storage records do not match the installed app
+     * versions. The reliability trigger should cause the package tracker to perform a check.
+     */
+    @Test
+    public void trackingEnabled_reliabilityTrigger_afterRebootTriggerNeededBecausePreviousFailed()
+            throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+        configureReliabilityConfigSettingsOk();
+
+        PackageVersions oldPackageVersions = new PackageVersions(1, 1);
+        PackageVersions currentPackageVersions = new PackageVersions(2, 2);
+
+        // Simulate there being a newer version installed than the one recorded in storage.
+        configureValidApplications(currentPackageVersions);
+
+        // Force the storage into a state we want.
+        mPackageStatusStorage.forceCheckStateForTests(
+                PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
+
+        // Simulate a reliability trigger.
+        mFakeIntentHelper.simulateReliabilityTrigger();
+
+        // Assert the PackageTracker did trigger an update.
+        checkUpdateCheckTriggered(currentPackageVersions);
+
+        // Simulate the update check completing successfully.
+        CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
+        mPackageTracker.recordCheckResult(checkToken, true /* success */);
+
+        // Check storage and reliability triggering state.
+        checkUpdateCheckSuccessful(currentPackageVersions);
+    }
+
+    /**
+     * Simulates persistent failures of the reliability check. It should stop after the configured
+     * number of checks.
+     */
+    @Test
+    public void trackingEnabled_reliabilityTrigger_repeatedFailures() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+
+        int retriesAllowed = 3;
+        int checkDelayMillis = 5 * 60 * 1000;
+        configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
+
+        PackageVersions oldPackageVersions = new PackageVersions(1, 1);
+        PackageVersions currentPackageVersions = new PackageVersions(2, 2);
+
+        // Simulate there being a newer version installed than the one recorded in storage.
+        configureValidApplications(currentPackageVersions);
+
+        // Force the storage into a state we want.
+        mPackageStatusStorage.forceCheckStateForTests(
+                PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
+
+        for (int i = 0; i < retriesAllowed + 1; i++) {
+            // Simulate a reliability trigger.
+            mFakeIntentHelper.simulateReliabilityTrigger();
+
+            // Assert the PackageTracker did trigger an update.
+            checkUpdateCheckTriggered(currentPackageVersions);
+
+            // Check the PackageTracker failure count before calling recordCheckResult.
+            assertEquals(i, mPackageTracker.getCheckFailureCountForTests());
+
+            // Simulate a check failure.
+            CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
+            mPackageTracker.recordCheckResult(checkToken, false /* success */);
+
+            // Peek inside the package tracker to make sure it is tracking failure counts properly.
+            assertEquals(i + 1, mPackageTracker.getCheckFailureCountForTests());
+
+            // Confirm nothing has changed.
+            mFakeIntentHelper.assertUpdateNotTriggered();
+            checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE,
+                    currentPackageVersions);
+
+            // Check reliability triggering is in the correct state.
+            if (i <= retriesAllowed) {
+                mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+            } else {
+                mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+            }
+        }
+    }
+
+    @Test
+    public void trackingEnabled_reliabilityTrigger_failureCountIsReset() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+
+        int retriesAllowed = 3;
+        int checkDelayMillis = 5 * 60 * 1000;
+        configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
+
+        PackageVersions oldPackageVersions = new PackageVersions(1, 1);
+        PackageVersions currentPackageVersions = new PackageVersions(2, 2);
+
+        // Simulate there being a newer version installed than the one recorded in storage.
+        configureValidApplications(currentPackageVersions);
+
+        // Force the storage into a state we want.
+        mPackageStatusStorage.forceCheckStateForTests(
+                PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
+
+        // Fail (retries - 1) times.
+        for (int i = 0; i < retriesAllowed - 1; i++) {
+            // Simulate a reliability trigger.
+            mFakeIntentHelper.simulateReliabilityTrigger();
+
+            // Assert the PackageTracker did trigger an update.
+            checkUpdateCheckTriggered(currentPackageVersions);
+
+            // Check the PackageTracker failure count before calling recordCheckResult.
+            assertEquals(i, mPackageTracker.getCheckFailureCountForTests());
+
+            // Simulate a check failure.
+            CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
+            mPackageTracker.recordCheckResult(checkToken, false /* success */);
+
+            // Peek inside the package tracker to make sure it is tracking failure counts properly.
+            assertEquals(i + 1, mPackageTracker.getCheckFailureCountForTests());
+
+            // Confirm nothing has changed.
+            mFakeIntentHelper.assertUpdateNotTriggered();
+            checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE,
+                    currentPackageVersions);
+
+            // Check reliability triggering is still enabled.
+            mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+        }
+
+        // Simulate a reliability trigger.
+        mFakeIntentHelper.simulateReliabilityTrigger();
+
+        // Assert the PackageTracker did trigger an update.
+        checkUpdateCheckTriggered(currentPackageVersions);
+
+        // Check the PackageTracker failure count before calling recordCheckResult.
+        assertEquals(retriesAllowed - 1, mPackageTracker.getCheckFailureCountForTests());
+
+        // On the last possible try, succeed.
+        CheckToken checkToken = mFakeIntentHelper.captureAndResetLastToken();
+        mPackageTracker.recordCheckResult(checkToken, true /* success */);
+
+        checkUpdateCheckSuccessful(currentPackageVersions);
+    }
+
+    /**
+     * Simulates reliability triggers happening too close together. Package tracker should ignore
+     * the ones it doesn't need.
+     */
+    @Test
+    public void trackingEnabled_reliabilityTrigger_tooSoon() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+
+        int retriesAllowed = 5;
+        int checkDelayMillis = 5 * 60 * 1000;
+        configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
+
+        PackageVersions oldPackageVersions = new PackageVersions(1, 1);
+        PackageVersions currentPackageVersions = new PackageVersions(2, 2);
+
+        // Simulate there being a newer version installed than the one recorded in storage.
+        configureValidApplications(currentPackageVersions);
+
+        // Force the storage into a state we want.
+        mPackageStatusStorage.forceCheckStateForTests(
+                PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, oldPackageVersions);
+
+        // Simulate a reliability trigger.
+        mFakeIntentHelper.simulateReliabilityTrigger();
+
+        // Assert the PackageTracker did trigger an update.
+        checkUpdateCheckTriggered(currentPackageVersions);
+        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
+
+        // Increment the clock, but not enough.
+        mFakeClock.incrementClock(checkDelayMillis - 1);
+
+        // Simulate a reliability trigger.
+        mFakeIntentHelper.simulateReliabilityTrigger();
+
+        // Assert the PackageTracker did not trigger an update.
+        mFakeIntentHelper.assertUpdateNotTriggered();
+        checkPackageStorageStatus(PackageStatus.CHECK_STARTED, currentPackageVersions);
+        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+
+        // Increment the clock slightly more. Should now consider the response overdue.
+        mFakeClock.incrementClock(2);
+
+        // Simulate a reliability trigger.
+        mFakeIntentHelper.simulateReliabilityTrigger();
+
+        // Triggering should have happened.
+        checkUpdateCheckTriggered(currentPackageVersions);
+        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
+
+        // Check a new token was generated.
+        assertFalse(token1.equals(token2));
+    }
+
+    /**
+     * Tests what happens when a package update doesn't complete and a reliability trigger cleans
+     * up for it.
+     */
+    @Test
+    public void trackingEnabled_reliabilityTrigger_afterPackageUpdateDidNotComplete()
+            throws Exception {
+
+        // Set up device configuration.
+        configureTrackingEnabled();
+
+        int retriesAllowed = 5;
+        int checkDelayMillis = 5 * 60 * 1000;
+        configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
+
+        PackageVersions currentPackageVersions = new PackageVersions(1, 1);
+        PackageVersions newPackageVersions = new PackageVersions(2, 2);
+
+        // Simulate there being a newer version installed than the one recorded in storage.
+        configureValidApplications(currentPackageVersions);
+
+        // Force the storage into a state we want.
+        mPackageStatusStorage.forceCheckStateForTests(
+                PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Simulate a reliability trigger.
+        simulatePackageInstallation(newPackageVersions);
+
+        // Assert the PackageTracker did trigger an update.
+        checkUpdateCheckTriggered(newPackageVersions);
+        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
+
+        // Increment the clock, but not enough.
+        mFakeClock.incrementClock(checkDelayMillis + 1);
+
+        // Simulate a reliability trigger.
+        mFakeIntentHelper.simulateReliabilityTrigger();
+
+        // Assert the PackageTracker triggered an update.
+        checkUpdateCheckTriggered(newPackageVersions);
+        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
+
+        // Check a new token was generated.
+        assertFalse(token1.equals(token2));
+
+        // Simulate the reliability check completing.
+        mPackageTracker.recordCheckResult(token2, true /* success */);
+
+        // Check everything is now as it should be.
+        checkUpdateCheckSuccessful(newPackageVersions);
+    }
+
+    /**
+     * Simulates a reliability trigger happening too soon after a package update trigger occurred.
+     */
+    @Test
+    public void trackingEnabled_reliabilityTriggerAfterUpdate_tooSoon() throws Exception {
+        // Set up device configuration.
+        configureTrackingEnabled();
+
+        int retriesAllowed = 5;
+        int checkDelayMillis = 5 * 60 * 1000;
+        configureReliabilityConfigSettings(retriesAllowed, checkDelayMillis);
+
+        PackageVersions currentPackageVersions = new PackageVersions(1, 1);
+        PackageVersions newPackageVersions = new PackageVersions(2, 2);
+
+        // Simulate there being a newer version installed than the one recorded in storage.
+        configureValidApplications(currentPackageVersions);
+
+        // Force the storage into a state we want.
+        mPackageStatusStorage.forceCheckStateForTests(
+                PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
+
+        // Initialize the package tracker.
+        mPackageTracker.start();
+
+        // Check the intent helper is properly configured.
+        checkIntentHelperInitializedAndReliabilityTrackingEnabled();
+
+        // Check the initial storage state.
+        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, currentPackageVersions);
+
+        // Simulate a package update trigger.
+        simulatePackageInstallation(newPackageVersions);
+
+        // Assert the PackageTracker did trigger an update.
+        checkUpdateCheckTriggered(newPackageVersions);
+        CheckToken token1 = mFakeIntentHelper.captureAndResetLastToken();
+
+        // Increment the clock, but not enough.
+        mFakeClock.incrementClock(checkDelayMillis - 1);
+
+        // Simulate a reliability trigger.
+        mFakeIntentHelper.simulateReliabilityTrigger();
+
+        // Assert the PackageTracker did not trigger an update.
+        mFakeIntentHelper.assertUpdateNotTriggered();
+        checkPackageStorageStatus(PackageStatus.CHECK_STARTED, newPackageVersions);
+        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+
+        // Increment the clock slightly more. Should now consider the response overdue.
+        mFakeClock.incrementClock(2);
+
+        // Simulate a reliability trigger.
+        mFakeIntentHelper.simulateReliabilityTrigger();
+
+        // Triggering should have happened.
+        checkUpdateCheckTriggered(newPackageVersions);
+        CheckToken token2 = mFakeIntentHelper.captureAndResetLastToken();
+
+        // Check a new token was generated.
+        assertFalse(token1.equals(token2));
+    }
+
+    private void simulatePackageInstallation(PackageVersions packageVersions) throws Exception {
+        configureApplicationsValidManifests(packageVersions);
+
+        // Simulate a tracked package being updated.
+        mFakeIntentHelper.simulatePackageUpdatedEvent();
+    }
+
+    /**
+     * Checks an update check was triggered, reliability triggering is therefore enabled and the
+     * storage state reflects that there is a check in progress.
+     */
+    private void checkUpdateCheckTriggered(PackageVersions packageVersions) {
+        // Assert the PackageTracker attempted to trigger an update.
+        mFakeIntentHelper.assertUpdateTriggered();
+
+        // If an update check was triggered reliability triggering should always be enabled to
+        // ensure that it can be completed if it fails.
+        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+
+        // Check the expected storage state.
+        checkPackageStorageStatus(PackageStatus.CHECK_STARTED, packageVersions);
+    }
+
+    private void checkUpdateCheckFailed(PackageVersions packageVersions) {
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+
+        // Assert the storage was updated.
+        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_FAILURE, packageVersions);
+    }
+
+    private void checkUpdateCheckSuccessful(PackageVersions packageVersions) {
+        // Check reliability triggering state.
+        mFakeIntentHelper.assertReliabilityTriggeringDisabled();
+
+        // Assert the storage was updated.
+        checkPackageStorageStatus(PackageStatus.CHECK_COMPLETED_SUCCESS, packageVersions);
+
+        // Peek inside the package tracker to make sure it is tracking failure counts properly.
+        assertEquals(0, mPackageTracker.getCheckFailureCountForTests());
+    }
+
+    private PackageVersions configureValidApplications() throws Exception {
+        configureValidApplications(INITIAL_APP_PACKAGE_VERSIONS);
+        return INITIAL_APP_PACKAGE_VERSIONS;
+    }
+
+    private void configureValidApplications(PackageVersions versions) throws Exception {
+        configureUpdateAppPackageOk(UPDATE_APP_PACKAGE_NAME);
+        configureDataAppPackageOk(DATA_APP_PACKAGE_NAME);
+        configureApplicationsValidManifests(versions);
+    }
+
+    private void configureApplicationsValidManifests(PackageVersions versions) throws Exception {
+        configureUpdateAppManifestOk(UPDATE_APP_PACKAGE_NAME);
+        configureDataAppManifestOk(DATA_APP_PACKAGE_NAME);
+        configureUpdateAppPackageVersion(UPDATE_APP_PACKAGE_NAME, versions.mUpdateAppVersion);
+        configureDataAppPackageVersion(DATA_APP_PACKAGE_NAME, versions.mDataAppVersion);
+    }
+
+    private void configureUpdateAppPackageVersion(String updateAppPackageName,
+            int updataAppPackageVersion) throws Exception {
+        when(mMockPackageManagerHelper.getInstalledPackageVersion(updateAppPackageName))
+                .thenReturn(updataAppPackageVersion);
+    }
+
+    private void configureDataAppPackageVersion(String dataAppPackageName,
+            int dataAppPackageVersion) throws Exception {
+        when(mMockPackageManagerHelper.getInstalledPackageVersion(dataAppPackageName))
+                .thenReturn(dataAppPackageVersion);
+    }
+
+    private void configureUpdateAppManifestOk(String updateAppPackageName) throws Exception {
+        Intent expectedIntent = RulesUpdaterContract.createUpdaterIntent(updateAppPackageName);
+        when(mMockPackageManagerHelper.receiverRegistered(
+                filterEquals(expectedIntent),
+                eq(RulesUpdaterContract.TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION)))
+                .thenReturn(true);
+        when(mMockPackageManagerHelper.usesPermission(
+                updateAppPackageName, RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION))
+                .thenReturn(true);
+    }
+
+    private void configureUpdateAppManifestBad(String updateAppPackageName) throws Exception {
+        Intent expectedIntent = RulesUpdaterContract.createUpdaterIntent(updateAppPackageName);
+        when(mMockPackageManagerHelper.receiverRegistered(
+                filterEquals(expectedIntent),
+                eq(RulesUpdaterContract.TRIGGER_TIME_ZONE_RULES_CHECK_PERMISSION)))
+                .thenReturn(false);
+        // Has permission, but that shouldn't matter if the check above is false.
+        when(mMockPackageManagerHelper.usesPermission(
+                updateAppPackageName, RulesUpdaterContract.UPDATE_TIME_ZONE_RULES_PERMISSION))
+                .thenReturn(true);
+    }
+
+    private void configureDataAppManifestOk(String dataAppPackageName) throws Exception {
+        when(mMockPackageManagerHelper.contentProviderRegistered(
+                TimeZoneRulesDataContract.AUTHORITY, dataAppPackageName))
+                .thenReturn(true);
+    }
+
+    private void configureDataAppManifestBad(String dataAppPackageName) throws Exception {
+        // Simulate the data app not exposing the content provider we require.
+        when(mMockPackageManagerHelper.contentProviderRegistered(
+                TimeZoneRulesDataContract.AUTHORITY, dataAppPackageName))
+                .thenReturn(false);
+    }
+
+    private void configureTrackingEnabled() {
+        when(mMockConfigHelper.isTrackingEnabled()).thenReturn(true);
+    }
+
+    private void configureTrackingDisabled() {
+        when(mMockConfigHelper.isTrackingEnabled()).thenReturn(false);
+    }
+
+    private void configureReliabilityConfigSettings(int retriesAllowed, int checkDelayMillis) {
+        when(mMockConfigHelper.getFailedCheckRetryCount()).thenReturn(retriesAllowed);
+        when(mMockConfigHelper.getCheckTimeAllowedMillis()).thenReturn(checkDelayMillis);
+    }
+
+    private void configureReliabilityConfigSettingsOk() {
+        configureReliabilityConfigSettings(5, 5 * 60 * 1000);
+    }
+
+    private void configureUpdateAppPackageOk(String updateAppPackageName) throws Exception {
+        when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(updateAppPackageName);
+        when(mMockPackageManagerHelper.isPrivilegedApp(updateAppPackageName)).thenReturn(true);
+    }
+
+    private void configureUpdateAppPackageNotPrivileged(String updateAppPackageName)
+            throws Exception {
+        when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(updateAppPackageName);
+        when(mMockPackageManagerHelper.isPrivilegedApp(updateAppPackageName)).thenReturn(false);
+    }
+
+    private void configureUpdateAppPackageNameMissing() {
+        when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(null);
+    }
+
+    private void configureDataAppPackageOk(String dataAppPackageName) throws Exception {
+        when(mMockConfigHelper.getDataAppPackageName()).thenReturn(dataAppPackageName);
+        when(mMockPackageManagerHelper.isPrivilegedApp(dataAppPackageName)).thenReturn(true);
+    }
+
+    private void configureDataAppPackageNotPrivileged(String dataAppPackageName)
+            throws Exception {
+        when(mMockConfigHelper.getUpdateAppPackageName()).thenReturn(dataAppPackageName);
+        when(mMockPackageManagerHelper.isPrivilegedApp(dataAppPackageName)).thenReturn(false);
+    }
+
+    private void configureDataAppPackageNameMissing() {
+        when(mMockConfigHelper.getDataAppPackageName()).thenThrow(new RuntimeException());
+    }
+
+    private void checkIntentHelperInitializedAndReliabilityTrackingEnabled() {
+        // Verify that calling start initialized the IntentHelper as well.
+        mFakeIntentHelper.assertInitialized(UPDATE_APP_PACKAGE_NAME, DATA_APP_PACKAGE_NAME);
+
+        // Assert that reliability tracking is always enabled after initialization.
+        mFakeIntentHelper.assertReliabilityTriggeringEnabled();
+    }
+
+    private void checkPackageStorageStatus(
+            int expectedCheckStatus, PackageVersions expectedPackageVersions) {
+        PackageStatus packageStatus = mPackageStatusStorage.getPackageStatus();
+        assertEquals(expectedCheckStatus, packageStatus.mCheckStatus);
+        assertEquals(expectedPackageVersions, packageStatus.mVersions);
+    }
+
+    private void checkPackageStorageStatusIsInitialOrReset() {
+        assertNull(mPackageStatusStorage.getPackageStatus());
+    }
+
+    private static CheckToken createArbitraryCheckToken() {
+        return new CheckToken(1, INITIAL_APP_PACKAGE_VERSIONS);
+    }
+
+    /**
+     * A fake IntentHelper implementation for use in tests.
+     */
+    private static class FakeIntentHelper implements IntentHelper {
+
+        private Listener mListener;
+        private String mUpdateAppPackageName;
+        private String mDataAppPackageName;
+
+        private CheckToken mLastToken;
+
+        private boolean mReliabilityTriggeringEnabled;
+
+        @Override
+        public void initialize(String updateAppPackageName, String dataAppPackageName,
+                Listener listener) {
+            assertNotNull(updateAppPackageName);
+            assertNotNull(dataAppPackageName);
+            assertNotNull(listener);
+            mListener = listener;
+            mUpdateAppPackageName = updateAppPackageName;
+            mDataAppPackageName = dataAppPackageName;
+        }
+
+        public void assertInitialized(
+                String expectedUpdateAppPackageName, String expectedDataAppPackageName) {
+            assertNotNull(mListener);
+            assertEquals(expectedUpdateAppPackageName, mUpdateAppPackageName);
+            assertEquals(expectedDataAppPackageName, mDataAppPackageName);
+        }
+
+        public void assertNotInitialized() {
+            assertNull(mListener);
+        }
+
+        @Override
+        public void sendTriggerUpdateCheck(CheckToken checkToken) {
+            if (mLastToken != null) {
+                fail("lastToken already set");
+            }
+            mLastToken = checkToken;
+        }
+
+        @Override
+        public void enableReliabilityTriggering() {
+            mReliabilityTriggeringEnabled = true;
+        }
+
+        @Override
+        public void disableReliabilityTriggering() {
+            mReliabilityTriggeringEnabled = false;
+        }
+
+        public void assertReliabilityTriggeringEnabled() {
+            assertTrue(mReliabilityTriggeringEnabled);
+        }
+
+        public void assertReliabilityTriggeringDisabled() {
+            assertFalse(mReliabilityTriggeringEnabled);
+        }
+
+        public void assertUpdateTriggered() {
+            assertNotNull(mLastToken);
+        }
+
+        public void assertUpdateNotTriggered() {
+            assertNull(mLastToken);
+        }
+
+        public CheckToken captureAndResetLastToken() {
+            CheckToken toReturn = mLastToken;
+            assertNotNull("No update triggered", toReturn);
+            mLastToken = null;
+            return toReturn;
+        }
+
+        public void simulatePackageUpdatedEvent() {
+            mListener.triggerUpdateIfNeeded(true);
+        }
+
+        public void simulateReliabilityTrigger() {
+            mListener.triggerUpdateIfNeeded(false);
+        }
+    }
+
+    private static class FakeClockHelper implements ClockHelper {
+
+        private long currentTime = 1000;
+
+        @Override
+        public long currentTimestamp() {
+            return currentTime;
+        }
+
+        public void incrementClock(long millis) {
+            currentTime += millis;
+        }
+    }
+
+    /**
+     * Registers a mockito parameter matcher that uses {@link Intent#filterEquals(Intent)}. to
+     * check the parameter against the intent supplied.
+     */
+    private static Intent filterEquals(final Intent expected) {
+        final Matcher<Intent> m = new BaseMatcher<Intent>() {
+            @Override
+            public boolean matches(Object actual) {
+                return actual != null && expected.filterEquals((Intent) actual);
+            }
+            @Override
+            public void describeTo(Description description) {
+                description.appendText(expected.toString());
+            }
+        };
+        return argThat(m);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/PackageVersionsTest.java b/services/tests/servicestests/src/com/android/server/timezone/PackageVersionsTest.java
new file mode 100644
index 0000000..a470f8f
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezone/PackageVersionsTest.java
@@ -0,0 +1,47 @@
+/*
+ * 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.server.timezone;
+
+import org.junit.Test;
+
+import android.support.test.filters.SmallTest;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+@SmallTest
+public class PackageVersionsTest {
+
+    @Test
+    public void equals() {
+        PackageVersions baseline =
+                new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
+        assertEquals(baseline, baseline);
+
+        PackageVersions deepEqual =
+                new PackageVersions(1 /* updateAppVersion */, 1 /* dataAppVersion */);
+        assertEquals(baseline, deepEqual);
+
+        PackageVersions differentUpdateAppVersion =
+                new PackageVersions(2 /* updateAppVersion */, 1 /* dataAppVersion */);
+        assertFalse(baseline.equals(differentUpdateAppVersion));
+
+        PackageVersions differentDataAppVersion =
+                new PackageVersions(1 /* updateAppVersion */, 2 /* dataAppVersion */);
+        assertFalse(baseline.equals(differentDataAppVersion));
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
new file mode 100644
index 0000000..a7f4c99
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/timezone/RulesManagerServiceTest.java
@@ -0,0 +1,924 @@
+/*
+ * 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.server.timezone;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import android.app.timezone.Callback;
+import android.app.timezone.DistroRulesVersion;
+import android.app.timezone.ICallback;
+import android.app.timezone.RulesManager;
+import android.app.timezone.RulesState;
+import android.os.ParcelFileDescriptor;
+
+import java.io.IOException;
+import java.util.concurrent.Executor;
+import javax.annotation.Nullable;
+import libcore.tzdata.shared2.DistroVersion;
+import libcore.tzdata.shared2.StagedDistroOperation;
+import libcore.tzdata.update2.TimeZoneDistroInstaller;
+
+import static com.android.server.timezone.RulesManagerService.REQUIRED_UPDATER_PERMISSION;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+/**
+ * White box interaction / unit testing of the {@link RulesManagerService}.
+ */
+public class RulesManagerServiceTest {
+
+    private RulesManagerService mRulesManagerService;
+
+    private FakeExecutor mFakeExecutor;
+    private PermissionHelper mMockPermissionHelper;
+    private FileDescriptorHelper mMockFileDescriptorHelper;
+    private PackageTracker mMockPackageTracker;
+    private TimeZoneDistroInstaller mMockTimeZoneDistroInstaller;
+
+    @Before
+    public void setUp() {
+        mFakeExecutor = new FakeExecutor();
+
+        mMockFileDescriptorHelper = mock(FileDescriptorHelper.class);
+        mMockPackageTracker = mock(PackageTracker.class);
+        mMockPermissionHelper = mock(PermissionHelper.class);
+        mMockTimeZoneDistroInstaller = mock(TimeZoneDistroInstaller.class);
+
+        mRulesManagerService = new RulesManagerService(
+                mMockPermissionHelper,
+                mFakeExecutor,
+                mMockFileDescriptorHelper,
+                mMockPackageTracker,
+                mMockTimeZoneDistroInstaller);
+    }
+
+    @Test(expected = SecurityException.class)
+    public void getRulesState_noCallerPermission() throws Exception {
+        configureCallerDoesNotHavePermission();
+        mRulesManagerService.getRulesState();
+    }
+
+    @Test(expected = SecurityException.class)
+    public void requestInstall_noCallerPermission() throws Exception {
+        configureCallerDoesNotHavePermission();
+        mRulesManagerService.requestInstall(null, null, null);
+    }
+
+    @Test(expected = SecurityException.class)
+    public void requestUninstall_noCallerPermission() throws Exception {
+        configureCallerDoesNotHavePermission();
+        mRulesManagerService.requestUninstall(null, null);
+    }
+
+    @Test(expected = SecurityException.class)
+    public void requestNothing_noCallerPermission() throws Exception {
+        configureCallerDoesNotHavePermission();
+        mRulesManagerService.requestNothing(null, true);
+    }
+
+    @Test
+    public void getRulesState_systemRulesError() throws Exception {
+        configureDeviceCannotReadSystemRulesVersion();
+
+        assertNull(mRulesManagerService.getRulesState());
+    }
+
+    @Test
+    public void getRulesState_stagedInstall() throws Exception {
+        configureCallerHasPermission();
+
+        configureDeviceSystemRulesVersion("2016a");
+
+        DistroVersion stagedDistroVersion = new DistroVersion(
+                DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
+                "2016c",
+                3);
+        configureStagedInstall(stagedDistroVersion);
+
+        DistroVersion installedDistroVersion = new DistroVersion(
+                DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
+                "2016b",
+                4);
+        configureInstalledDistroVersion(installedDistroVersion);
+
+        DistroRulesVersion stagedDistroRulesVersion = new DistroRulesVersion(
+                stagedDistroVersion.rulesVersion, stagedDistroVersion.revision);
+        DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion(
+                installedDistroVersion.rulesVersion, installedDistroVersion.revision);
+        RulesState expectedRuleState = new RulesState(
+                "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
+                false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_INSTALL, stagedDistroRulesVersion,
+                RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion);
+        assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
+    }
+
+    @Test
+    public void getRulesState_nothingStaged() throws Exception {
+        configureCallerHasPermission();
+
+        configureDeviceSystemRulesVersion("2016a");
+
+        configureNoStagedOperation();
+
+        DistroVersion installedDistroVersion = new DistroVersion(
+                DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
+                "2016b",
+                4);
+        configureInstalledDistroVersion(installedDistroVersion);
+
+        DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion(
+                installedDistroVersion.rulesVersion, installedDistroVersion.revision);
+        RulesState expectedRuleState = new RulesState(
+                "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
+                false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion);
+        assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
+    }
+
+    @Test
+    public void getRulesState_uninstallStaged() throws Exception {
+        configureCallerHasPermission();
+
+        configureDeviceSystemRulesVersion("2016a");
+
+        configureStagedUninstall();
+
+        DistroVersion installedDistroVersion = new DistroVersion(
+                DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
+                "2016b",
+                4);
+        configureInstalledDistroVersion(installedDistroVersion);
+
+        DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion(
+                installedDistroVersion.rulesVersion, installedDistroVersion.revision);
+        RulesState expectedRuleState = new RulesState(
+                "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
+                false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_UNINSTALL, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion);
+        assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
+    }
+
+    @Test
+    public void getRulesState_installedRulesError() throws Exception {
+        configureCallerHasPermission();
+
+        String systemRulesVersion = "2016a";
+        configureDeviceSystemRulesVersion(systemRulesVersion);
+
+        configureStagedUninstall();
+        configureDeviceCannotReadInstalledDistroVersion();
+
+        RulesState expectedRuleState = new RulesState(
+                "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
+                false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_UNINSTALL, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */);
+        assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
+    }
+
+    @Test
+    public void getRulesState_stagedRulesError() throws Exception {
+        configureCallerHasPermission();
+
+        String systemRulesVersion = "2016a";
+        configureDeviceSystemRulesVersion(systemRulesVersion);
+
+        configureDeviceCannotReadStagedDistroOperation();
+
+        DistroVersion installedDistroVersion = new DistroVersion(
+                DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
+                "2016b",
+                4);
+        configureInstalledDistroVersion(installedDistroVersion);
+
+        DistroRulesVersion installedDistroRulesVersion = new DistroRulesVersion(
+                installedDistroVersion.rulesVersion, installedDistroVersion.revision);
+        RulesState expectedRuleState = new RulesState(
+                "2016a", RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
+                false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_INSTALLED, installedDistroRulesVersion);
+        assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
+    }
+
+    @Test
+    public void getRulesState_noInstalledRules() throws Exception {
+        configureCallerHasPermission();
+
+        String systemRulesVersion = "2016a";
+        configureDeviceSystemRulesVersion(systemRulesVersion);
+        configureNoStagedOperation();
+        configureInstalledDistroVersion(null);
+
+        RulesState expectedRuleState = new RulesState(
+                systemRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
+                false /* operationInProgress */,
+                RulesState.STAGED_OPERATION_NONE, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_NONE, null /* installedDistroRulesVersion */);
+        assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
+    }
+
+    @Test
+    public void getRulesState_operationInProgress() throws Exception {
+        configureCallerHasPermission();
+
+        String systemRulesVersion = "2016a";
+        String installedRulesVersion = "2016b";
+        int revision = 3;
+
+        configureDeviceSystemRulesVersion(systemRulesVersion);
+
+        DistroVersion installedDistroVersion = new DistroVersion(
+                DistroVersion.CURRENT_FORMAT_MAJOR_VERSION,
+                DistroVersion.CURRENT_FORMAT_MINOR_VERSION - 1,
+                installedRulesVersion,
+                revision);
+        configureInstalledDistroVersion(installedDistroVersion);
+
+        byte[] expectedContent = createArbitraryBytes(1000);
+        ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
+        configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+
+        // Start an async operation so there is one in progress. The mFakeExecutor won't actually
+        // execute it.
+        byte[] tokenBytes = createArbitraryTokenBytes();
+        ICallback callback = new StubbedCallback();
+
+        mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback);
+
+        RulesState expectedRuleState = new RulesState(
+                systemRulesVersion, RulesManagerService.DISTRO_FORMAT_VERSION_SUPPORTED,
+                true /* operationInProgress */,
+                RulesState.STAGED_OPERATION_UNKNOWN, null /* stagedDistroRulesVersion */,
+                RulesState.DISTRO_STATUS_UNKNOWN, null /* installedDistroRulesVersion */);
+        assertEquals(expectedRuleState, mRulesManagerService.getRulesState());
+    }
+
+    @Test
+    public void requestInstall_operationInProgress() throws Exception {
+        configureCallerHasPermission();
+
+        byte[] expectedContent = createArbitraryBytes(1000);
+        ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
+        configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+
+        byte[] tokenBytes = createArbitraryTokenBytes();
+        ICallback callback = new StubbedCallback();
+
+        // First request should succeed.
+        assertEquals(RulesManager.SUCCESS,
+                mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
+
+        // Something async should be enqueued. Clear it but do not execute it so we can detect the
+        // second request does nothing.
+        mFakeExecutor.getAndResetLastCommand();
+
+        // Second request should fail.
+        assertEquals(RulesManager.ERROR_OPERATION_IN_PROGRESS,
+                mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
+
+        // Assert nothing async was enqueued.
+        mFakeExecutor.assertNothingQueued();
+        verifyNoInstallerCallsMade();
+        verifyNoPackageTrackerCallsMade();
+    }
+
+    @Test
+    public void requestInstall_badToken() throws Exception {
+        configureCallerHasPermission();
+
+        byte[] expectedContent = createArbitraryBytes(1000);
+        ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
+        configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+
+        byte[] badTokenBytes = new byte[2];
+        ICallback callback = new StubbedCallback();
+
+        try {
+            mRulesManagerService.requestInstall(parcelFileDescriptor, badTokenBytes, callback);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // Assert nothing async was enqueued.
+        mFakeExecutor.assertNothingQueued();
+        verifyNoInstallerCallsMade();
+        verifyNoPackageTrackerCallsMade();
+    }
+
+    @Test
+    public void requestInstall_nullParcelFileDescriptor() throws Exception {
+        configureCallerHasPermission();
+
+        ParcelFileDescriptor parcelFileDescriptor = null;
+        byte[] tokenBytes = createArbitraryTokenBytes();
+        ICallback callback = new StubbedCallback();
+
+        try {
+            mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        // Assert nothing async was enqueued.
+        mFakeExecutor.assertNothingQueued();
+        verifyNoInstallerCallsMade();
+        verifyNoPackageTrackerCallsMade();
+    }
+
+    @Test
+    public void requestInstall_nullCallback() throws Exception {
+        configureCallerHasPermission();
+
+        ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
+        byte[] tokenBytes = createArbitraryTokenBytes();
+        ICallback callback = null;
+
+        try {
+            mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        // Assert nothing async was enqueued.
+        mFakeExecutor.assertNothingQueued();
+        verifyNoInstallerCallsMade();
+        verifyNoPackageTrackerCallsMade();
+    }
+
+    @Test
+    public void requestInstall_asyncSuccess() throws Exception {
+        configureCallerHasPermission();
+
+        ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
+        byte[] expectedContent = createArbitraryBytes(1000);
+        configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+
+        CheckToken token = createArbitraryToken();
+        byte[] tokenBytes = token.toByteArray();
+
+        TestCallback callback = new TestCallback();
+
+        // Request the install.
+        assertEquals(RulesManager.SUCCESS,
+                mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
+
+        // Assert nothing has happened yet.
+        callback.assertNoResultReceived();
+        verifyNoInstallerCallsMade();
+        verifyNoPackageTrackerCallsMade();
+
+        // Set up the installer.
+        configureStageInstallExpectation(expectedContent, TimeZoneDistroInstaller.INSTALL_SUCCESS);
+
+        // Simulate the async execution.
+        mFakeExecutor.simulateAsyncExecutionOfLastCommand();
+
+        // Verify the expected calls were made to other components.
+        verifyStageInstallCalled(expectedContent);
+        verifyPackageTrackerCalled(token, true /* success */);
+
+        // Check the callback was called.
+        callback.assertResultReceived(Callback.SUCCESS);
+    }
+
+    @Test
+    public void requestInstall_nullTokenBytes() throws Exception {
+        configureCallerHasPermission();
+
+        ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
+        byte[] expectedContent = createArbitraryBytes(1000);
+        configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+
+        TestCallback callback = new TestCallback();
+
+        // Request the install.
+        assertEquals(RulesManager.SUCCESS,
+                mRulesManagerService.requestInstall(
+                        parcelFileDescriptor, null /* tokenBytes */, callback));
+
+        // Assert nothing has happened yet.
+        verifyNoInstallerCallsMade();
+        callback.assertNoResultReceived();
+
+        // Set up the installer.
+        configureStageInstallExpectation(expectedContent, TimeZoneDistroInstaller.INSTALL_SUCCESS);
+
+        // Simulate the async execution.
+        mFakeExecutor.simulateAsyncExecutionOfLastCommand();
+
+        // Verify the expected calls were made to other components.
+        verifyStageInstallCalled(expectedContent);
+        verifyPackageTrackerCalled(null /* expectedToken */, true /* success */);
+
+        // Check the callback was received.
+        callback.assertResultReceived(Callback.SUCCESS);
+    }
+
+    @Test
+    public void requestInstall_asyncInstallFail() throws Exception {
+        configureCallerHasPermission();
+
+        byte[] expectedContent = createArbitraryBytes(1000);
+        ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
+        configureParcelFileDescriptorReadSuccess(parcelFileDescriptor, expectedContent);
+
+        CheckToken token = createArbitraryToken();
+        byte[] tokenBytes = token.toByteArray();
+
+        TestCallback callback = new TestCallback();
+
+        // Request the install.
+        assertEquals(RulesManager.SUCCESS,
+                mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
+
+        // Assert nothing has happened yet.
+        verifyNoInstallerCallsMade();
+        callback.assertNoResultReceived();
+
+        // Set up the installer.
+        configureStageInstallExpectation(
+                expectedContent, TimeZoneDistroInstaller.INSTALL_FAIL_VALIDATION_ERROR);
+
+        // Simulate the async execution.
+        mFakeExecutor.simulateAsyncExecutionOfLastCommand();
+
+        // Verify the expected calls were made to other components.
+        verifyStageInstallCalled(expectedContent);
+
+        // Validation failure is treated like a successful check: repeating it won't improve things.
+        boolean expectedSuccess = true;
+        verifyPackageTrackerCalled(token, expectedSuccess);
+
+        // Check the callback was received.
+        callback.assertResultReceived(Callback.ERROR_INSTALL_VALIDATION_ERROR);
+    }
+
+    @Test
+    public void requestInstall_asyncParcelFileDescriptorReadFail() throws Exception {
+        configureCallerHasPermission();
+
+        ParcelFileDescriptor parcelFileDescriptor = createFakeParcelFileDescriptor();
+        configureParcelFileDescriptorReadFailure(parcelFileDescriptor);
+
+        CheckToken token = createArbitraryToken();
+        byte[] tokenBytes = token.toByteArray();
+
+        TestCallback callback = new TestCallback();
+
+        // Request the install.
+        assertEquals(RulesManager.SUCCESS,
+                mRulesManagerService.requestInstall(parcelFileDescriptor, tokenBytes, callback));
+
+        // Simulate the async execution.
+        mFakeExecutor.simulateAsyncExecutionOfLastCommand();
+
+        // Verify nothing else happened.
+        verifyNoInstallerCallsMade();
+
+        // A failure to read the ParcelFileDescriptor is treated as a failure. It might be the
+        // result of a file system error. This is a fairly arbitrary choice.
+        verifyPackageTrackerCalled(token, false /* success */);
+
+        verifyNoPackageTrackerCallsMade();
+
+        // Check the callback was received.
+        callback.assertResultReceived(Callback.ERROR_UNKNOWN_FAILURE);
+    }
+
+    @Test
+    public void requestUninstall_operationInProgress() throws Exception {
+        configureCallerHasPermission();
+
+        byte[] tokenBytes = createArbitraryTokenBytes();
+        ICallback callback = new StubbedCallback();
+
+        // First request should succeed.
+        assertEquals(RulesManager.SUCCESS,
+                mRulesManagerService.requestUninstall(tokenBytes, callback));
+
+        // Something async should be enqueued. Clear it but do not execute it so we can detect the
+        // second request does nothing.
+        mFakeExecutor.getAndResetLastCommand();
+
+        // Second request should fail.
+        assertEquals(RulesManager.ERROR_OPERATION_IN_PROGRESS,
+                mRulesManagerService.requestUninstall(tokenBytes, callback));
+
+        // Assert nothing async was enqueued.
+        mFakeExecutor.assertNothingQueued();
+        verifyNoInstallerCallsMade();
+        verifyNoPackageTrackerCallsMade();
+    }
+
+    @Test
+    public void requestUninstall_badToken() throws Exception {
+        configureCallerHasPermission();
+
+        byte[] badTokenBytes = new byte[2];
+        ICallback callback = new StubbedCallback();
+
+        try {
+            mRulesManagerService.requestUninstall(badTokenBytes, callback);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // Assert nothing async was enqueued.
+        mFakeExecutor.assertNothingQueued();
+        verifyNoInstallerCallsMade();
+        verifyNoPackageTrackerCallsMade();
+    }
+
+    @Test
+    public void requestUninstall_nullCallback() throws Exception {
+        configureCallerHasPermission();
+
+        byte[] tokenBytes = createArbitraryTokenBytes();
+        ICallback callback = null;
+
+        try {
+            mRulesManagerService.requestUninstall(tokenBytes, callback);
+            fail();
+        } catch (NullPointerException expected) {}
+
+        // Assert nothing async was enqueued.
+        mFakeExecutor.assertNothingQueued();
+        verifyNoInstallerCallsMade();
+        verifyNoPackageTrackerCallsMade();
+    }
+
+    @Test
+    public void requestUninstall_asyncSuccess() throws Exception {
+        configureCallerHasPermission();
+
+        CheckToken token = createArbitraryToken();
+        byte[] tokenBytes = token.toByteArray();
+
+        TestCallback callback = new TestCallback();
+
+        // Request the uninstall.
+        assertEquals(RulesManager.SUCCESS,
+                mRulesManagerService.requestUninstall(tokenBytes, callback));
+
+        // Assert nothing has happened yet.
+        callback.assertNoResultReceived();
+        verifyNoInstallerCallsMade();
+        verifyNoPackageTrackerCallsMade();
+
+        // Set up the installer.
+        configureStageUninstallExpectation(true /* success */);
+
+        // Simulate the async execution.
+        mFakeExecutor.simulateAsyncExecutionOfLastCommand();
+
+        // Verify the expected calls were made to other components.
+        verifyStageUninstallCalled();
+        verifyPackageTrackerCalled(token, true /* success */);
+
+        // Check the callback was called.
+        callback.assertResultReceived(Callback.SUCCESS);
+    }
+
+    @Test
+    public void requestUninstall_nullTokenBytes() throws Exception {
+        configureCallerHasPermission();
+
+        TestCallback callback = new TestCallback();
+
+        // Request the uninstall.
+        assertEquals(RulesManager.SUCCESS,
+                mRulesManagerService.requestUninstall(null /* tokenBytes */, callback));
+
+        // Assert nothing has happened yet.
+        verifyNoInstallerCallsMade();
+        callback.assertNoResultReceived();
+
+        // Set up the installer.
+        configureStageUninstallExpectation(true /* success */);
+
+        // Simulate the async execution.
+        mFakeExecutor.simulateAsyncExecutionOfLastCommand();
+
+        // Verify the expected calls were made to other components.
+        verifyStageUninstallCalled();
+        verifyPackageTrackerCalled(null /* expectedToken */, true /* success */);
+
+        // Check the callback was received.
+        callback.assertResultReceived(Callback.SUCCESS);
+    }
+
+    @Test
+    public void requestUninstall_asyncUninstallFail() throws Exception {
+        configureCallerHasPermission();
+
+        CheckToken token = createArbitraryToken();
+        byte[] tokenBytes = token.toByteArray();
+
+        TestCallback callback = new TestCallback();
+
+        // Request the uninstall.
+        assertEquals(RulesManager.SUCCESS,
+                mRulesManagerService.requestUninstall(tokenBytes, callback));
+
+        // Assert nothing has happened yet.
+        verifyNoInstallerCallsMade();
+        callback.assertNoResultReceived();
+
+        // Set up the installer.
+        configureStageUninstallExpectation(false /* success */);
+
+        // Simulate the async execution.
+        mFakeExecutor.simulateAsyncExecutionOfLastCommand();
+
+        // Verify the expected calls were made to other components.
+        verifyStageUninstallCalled();
+        verifyPackageTrackerCalled(token, false /* success */);
+
+        // Check the callback was received.
+        callback.assertResultReceived(Callback.ERROR_UNKNOWN_FAILURE);
+    }
+
+    @Test
+    public void requestNothing_operationInProgressOk() throws Exception {
+        configureCallerHasPermission();
+
+        // Set up a parallel operation.
+        assertEquals(RulesManager.SUCCESS,
+                mRulesManagerService.requestUninstall(null, new StubbedCallback()));
+        // Something async should be enqueued. Clear it but do not execute it to simulate it still
+        // being in progress.
+        mFakeExecutor.getAndResetLastCommand();
+
+        CheckToken token = createArbitraryToken();
+        byte[] tokenBytes = token.toByteArray();
+
+        // Make the call.
+        mRulesManagerService.requestNothing(tokenBytes, true /* success */);
+
+        // Assert nothing async was enqueued.
+        mFakeExecutor.assertNothingQueued();
+
+        // Verify the expected calls were made to other components.
+        verifyPackageTrackerCalled(token, true /* success */);
+        verifyNoInstallerCallsMade();
+    }
+
+    @Test
+    public void requestNothing_badToken() throws Exception {
+        configureCallerHasPermission();
+
+        byte[] badTokenBytes = new byte[2];
+
+        try {
+            mRulesManagerService.requestNothing(badTokenBytes, true /* success */);
+            fail();
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // Assert nothing async was enqueued.
+        mFakeExecutor.assertNothingQueued();
+
+        // Assert no other calls were made.
+        verifyNoInstallerCallsMade();
+        verifyNoPackageTrackerCallsMade();
+    }
+
+    @Test
+    public void requestNothing() throws Exception {
+        configureCallerHasPermission();
+
+        CheckToken token = createArbitraryToken();
+        byte[] tokenBytes = token.toByteArray();
+
+        // Make the call.
+        mRulesManagerService.requestNothing(tokenBytes, false /* success */);
+
+        // Assert everything required was done.
+        verifyNoInstallerCallsMade();
+        verifyPackageTrackerCalled(token, false /* success */);
+    }
+
+    @Test
+    public void requestNothing_nullTokenBytes() throws Exception {
+        configureCallerHasPermission();
+
+        // Make the call.
+        mRulesManagerService.requestNothing(null /* tokenBytes */, true /* success */);
+
+        // Assert everything required was done.
+        verifyNoInstallerCallsMade();
+        verifyPackageTrackerCalled(null /* token */, true /* success */);
+    }
+
+    private void verifyNoPackageTrackerCallsMade() {
+        verifyNoMoreInteractions(mMockPackageTracker);
+        reset(mMockPackageTracker);
+    }
+
+    private void verifyPackageTrackerCalled(
+            CheckToken expectedCheckToken, boolean expectedSuccess) {
+        verify(mMockPackageTracker).recordCheckResult(expectedCheckToken, expectedSuccess);
+        reset(mMockPackageTracker);
+    }
+
+    private void configureCallerHasPermission() throws Exception {
+        doNothing()
+                .when(mMockPermissionHelper)
+                .enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
+    }
+
+    private void configureCallerDoesNotHavePermission() {
+        doThrow(new SecurityException("Simulated permission failure"))
+                .when(mMockPermissionHelper)
+                .enforceCallerHasPermission(REQUIRED_UPDATER_PERMISSION);
+    }
+
+    private void configureParcelFileDescriptorReadSuccess(ParcelFileDescriptor parcelFileDescriptor,
+            byte[] content) throws Exception {
+        when(mMockFileDescriptorHelper.readFully(parcelFileDescriptor)).thenReturn(content);
+    }
+
+    private void configureParcelFileDescriptorReadFailure(ParcelFileDescriptor parcelFileDescriptor)
+            throws Exception {
+        when(mMockFileDescriptorHelper.readFully(parcelFileDescriptor))
+                .thenThrow(new IOException("Simulated failure"));
+    }
+
+    private void configureStageInstallExpectation(byte[] expectedContent, int resultCode)
+            throws Exception {
+        when(mMockTimeZoneDistroInstaller.stageInstallWithErrorCode(eq(expectedContent)))
+                .thenReturn(resultCode);
+    }
+
+    private void configureStageUninstallExpectation(boolean success) throws Exception {
+        doReturn(success).when(mMockTimeZoneDistroInstaller).stageUninstall();
+    }
+
+    private void verifyStageInstallCalled(byte[] expectedContent) throws Exception {
+        verify(mMockTimeZoneDistroInstaller).stageInstallWithErrorCode(eq(expectedContent));
+        verifyNoMoreInteractions(mMockTimeZoneDistroInstaller);
+        reset(mMockTimeZoneDistroInstaller);
+    }
+
+    private void verifyStageUninstallCalled() throws Exception {
+        verify(mMockTimeZoneDistroInstaller).stageUninstall();
+        verifyNoMoreInteractions(mMockTimeZoneDistroInstaller);
+        reset(mMockTimeZoneDistroInstaller);
+    }
+
+    private void verifyNoInstallerCallsMade() {
+        verifyNoMoreInteractions(mMockTimeZoneDistroInstaller);
+        reset(mMockTimeZoneDistroInstaller);
+    }
+
+    private static byte[] createArbitraryBytes(int length) {
+        byte[] bytes = new byte[length];
+        for (int i = 0; i < length; i++) {
+            bytes[i] = (byte) i;
+        }
+        return bytes;
+    }
+
+    private byte[] createArbitraryTokenBytes() {
+        return createArbitraryToken().toByteArray();
+    }
+
+    private CheckToken createArbitraryToken() {
+        return new CheckToken(1, new PackageVersions(1, 1));
+    }
+
+    private ParcelFileDescriptor createFakeParcelFileDescriptor() {
+        return new ParcelFileDescriptor((ParcelFileDescriptor) null);
+    }
+
+    private void configureDeviceSystemRulesVersion(String systemRulesVersion) throws Exception {
+        when(mMockTimeZoneDistroInstaller.getSystemRulesVersion()).thenReturn(systemRulesVersion);
+    }
+
+    private void configureInstalledDistroVersion(@Nullable DistroVersion installedDistroVersion)
+            throws Exception {
+        when(mMockTimeZoneDistroInstaller.getInstalledDistroVersion())
+                .thenReturn(installedDistroVersion);
+    }
+
+    private void configureStagedInstall(DistroVersion stagedDistroVersion) throws Exception {
+        when(mMockTimeZoneDistroInstaller.getStagedDistroOperation())
+                .thenReturn(StagedDistroOperation.install(stagedDistroVersion));
+    }
+
+    private void configureStagedUninstall() throws Exception {
+        when(mMockTimeZoneDistroInstaller.getStagedDistroOperation())
+                .thenReturn(StagedDistroOperation.uninstall());
+    }
+
+    private void configureNoStagedOperation() throws Exception {
+        when(mMockTimeZoneDistroInstaller.getStagedDistroOperation()).thenReturn(null);
+    }
+
+    private void configureDeviceCannotReadStagedDistroOperation() throws Exception {
+        when(mMockTimeZoneDistroInstaller.getStagedDistroOperation())
+                .thenThrow(new IOException("Simulated failure"));
+    }
+
+    private void configureDeviceCannotReadSystemRulesVersion() throws Exception {
+        when(mMockTimeZoneDistroInstaller.getSystemRulesVersion())
+                .thenThrow(new IOException("Simulated failure"));
+    }
+
+    private void configureDeviceCannotReadInstalledDistroVersion() throws Exception {
+        when(mMockTimeZoneDistroInstaller.getInstalledDistroVersion())
+                .thenThrow(new IOException("Simulated failure"));
+    }
+
+    private static class FakeExecutor implements Executor {
+
+        private Runnable mLastCommand;
+
+        @Override
+        public void execute(Runnable command) {
+            assertNull(mLastCommand);
+            assertNotNull(command);
+            mLastCommand = command;
+        }
+
+        public Runnable getAndResetLastCommand() {
+            assertNotNull(mLastCommand);
+            Runnable toReturn = mLastCommand;
+            mLastCommand = null;
+            return toReturn;
+        }
+
+        public void simulateAsyncExecutionOfLastCommand() {
+            Runnable toRun = getAndResetLastCommand();
+            toRun.run();
+        }
+
+        public void assertNothingQueued() {
+            assertNull(mLastCommand);
+        }
+    }
+
+    private static class TestCallback extends ICallback.Stub {
+
+        private boolean mOnFinishedCalled;
+        private int mLastError;
+
+        @Override
+        public void onFinished(int error) {
+            assertFalse(mOnFinishedCalled);
+            mOnFinishedCalled = true;
+            mLastError = error;
+        }
+
+        public void assertResultReceived(int expectedResult) {
+            assertTrue(mOnFinishedCalled);
+            assertEquals(expectedResult, mLastError);
+        }
+
+        public void assertNoResultReceived() {
+            assertFalse(mOnFinishedCalled);
+        }
+    }
+
+    private static class StubbedCallback extends ICallback.Stub {
+        @Override
+        public void onFinished(int error) {
+            fail("Unexpected call");
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
index a23a6b22..649de4a 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
@@ -20,6 +20,7 @@
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 
+import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
 
@@ -33,8 +34,7 @@
  * runtest frameworks-services -c com.android.server.wm.TaskSnapshotCacheTest
  */
 @SmallTest
-// TODO(b/35196891): Add back to presubmit once the bug is fixed.
-//@Presubmit
+@Presubmit
 @RunWith(AndroidJUnit4.class)
 public class TaskSnapshotCacheTest extends TaskSnapshotPersisterTestBase {
 
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
index 18d0c32..8146763 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotPersisterTestBase.java
@@ -68,7 +68,11 @@
     }
 
     private void cleanDirectory() {
-        for (File file : new File(sFilesDir, "snapshots").listFiles()) {
+        final File[] files = new File(sFilesDir, "snapshots").listFiles();
+        if (files == null) {
+            return;
+        }
+        for (File file : files) {
             if (!file.isDirectory()) {
                 file.delete();
             }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
index 47ced99..d9349ed 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestUtils.java
@@ -66,8 +66,7 @@
     /** Creates a {@link Task} and adds it to the specified {@link TaskStack}. */
     public static Task createTaskInStack(WindowManagerService service, TaskStack stack,
             int userId) {
-        final Task newTask = new Task(WindowTestUtils.sNextTaskId++, stack, userId, service, null,
-                EMPTY, 0, false,
+        final Task newTask = new Task(sNextTaskId++, stack, userId, service, null, EMPTY, 0, false,
                 false, new ActivityManager.TaskDescription(), null);
         stack.addTask(newTask, POSITION_TOP);
         return newTask;
@@ -92,7 +91,7 @@
     public static class TestAppWindowToken extends AppWindowToken {
 
         TestAppWindowToken(DisplayContent dc) {
-            super(dc.mService, null, false, dc, true /* fillsParent */,
+            super(dc.mService, new IApplicationToken.Stub() {}, false, dc, true /* fillsParent */,
                     null /* overrideConfig */, null /* bounds */);
         }
 
diff --git a/services/tests/shortcutmanagerutils/Android.mk b/services/tests/shortcutmanagerutils/Android.mk
index dc97599..c7657f6 100644
--- a/services/tests/shortcutmanagerutils/Android.mk
+++ b/services/tests/shortcutmanagerutils/Android.mk
@@ -20,7 +20,8 @@
     $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := \
-    mockito-target
+    mockito-target \
+    legacy-android-test
 
 LOCAL_MODULE_TAGS := optional
 
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index e13665b..dae74db 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -16,6 +16,8 @@
 
 package com.android.server.usage;
 
+import static com.android.internal.util.ArrayUtils.defeatNullable;
+
 import android.app.AppOpsManager;
 import android.app.usage.ExternalStorageStats;
 import android.app.usage.IStorageStatsManager;
@@ -112,9 +114,12 @@
         mStorage.registerListener(new StorageEventListener() {
             @Override
             public void onVolumeStateChanged(VolumeInfo vol, int oldState, int newState) {
-                if ((vol.type == VolumeInfo.TYPE_PRIVATE)
-                        && (newState == VolumeInfo.STATE_MOUNTED)) {
-                    invalidateMounts();
+                switch (vol.type) {
+                    case VolumeInfo.TYPE_PRIVATE:
+                    case VolumeInfo.TYPE_EMULATED:
+                        if (newState == VolumeInfo.STATE_MOUNTED) {
+                            invalidateMounts();
+                        }
                 }
             }
         });
@@ -178,9 +183,11 @@
         long cacheBytes = 0;
         final long token = Binder.clearCallingIdentity();
         try {
-            for (UserInfo user : mUser.getUsers()) {
-                final StorageStats stats = queryStatsForUser(volumeUuid, user.id, null);
-                cacheBytes += stats.cacheBytes;
+            if (isQuotaSupported(volumeUuid, callingPackage)) {
+                for (UserInfo user : mUser.getUsers()) {
+                    final StorageStats stats = queryStatsForUser(volumeUuid, user.id, null);
+                    cacheBytes += stats.cacheBytes;
+                }
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -232,7 +239,7 @@
             enforcePermission(Binder.getCallingUid(), callingPackage);
         }
 
-        if (mPackage.getPackagesForUid(appInfo.uid).length == 1) {
+        if (defeatNullable(mPackage.getPackagesForUid(appInfo.uid)).length == 1) {
             // Only one package inside UID means we can fast-path
             return queryStatsForUid(volumeUuid, appInfo.uid, callingPackage);
         } else {
@@ -276,7 +283,7 @@
             enforcePermission(Binder.getCallingUid(), callingPackage);
         }
 
-        final String[] packageNames = mPackage.getPackagesForUid(uid);
+        final String[] packageNames = defeatNullable(mPackage.getPackagesForUid(uid));
         final long[] ceDataInodes = new long[packageNames.length];
         String[] codePaths = new String[0];
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e0788ca..fe37995 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -898,13 +898,6 @@
             "broadcast_emergency_call_state_changes_bool";
 
     /**
-     * Cell broadcast additional channels enbled by the carrier
-     * @hide
-     */
-    public static final String KEY_CARRIER_ADDITIONAL_CBS_CHANNELS_STRINGS =
-            "carrier_additional_cbs_channels_strings";
-
-    /**
       * Indicates whether STK LAUNCH_BROWSER command is disabled.
       * If {@code true}, then the browser will not be launched
       * on UI for the LAUNCH_BROWSER STK command.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index c20eb30..984344c 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5371,9 +5371,10 @@
         try {
             ITelephony telephony = getITelephony();
             if (telephony != null)
-                return telephony.isDataConnectivityPossible();
+                return telephony.isDataConnectivityPossible(getSubId(SubscriptionManager
+                        .getDefaultDataSubscriptionId()));
         } catch (RemoteException e) {
-            Log.e(TAG, "Error calling ITelephony#isDataConnectivityPossible", e);
+            Log.e(TAG, "Error calling ITelephony#isDataAllowed", e);
         }
         return false;
     }
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index f01e4c0..256e13b 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -106,6 +106,7 @@
     public static final int EVENT_REDIRECTION_DETECTED = BASE + 44;
     public static final int EVENT_PCO_DATA_RECEIVED = BASE + 45;
     public static final int EVENT_SET_CARRIER_DATA_ENABLED = BASE + 46;
+    public static final int EVENT_DATA_RECONNECT = BASE + 47;
 
     /***** Constants *****/
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 621ccd6..bbfc490 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -370,7 +370,7 @@
     /**
      * Report whether data connectivity is possible.
      */
-    boolean isDataConnectivityPossible();
+    boolean isDataConnectivityPossible(int subId);
 
     Bundle getCellLocation(String callingPkg);
 
diff --git a/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
index bce5680..f28d126 100644
--- a/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SmsCbConstants.java
@@ -34,18 +34,6 @@
     public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_50
             = 0x0032;
 
-    /** Channel 911 required by Taiwan NCC. ID 0~999 is allocated by GSMA */
-    public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_911
-            = 0x038F; // 911
-
-    /** Channel 919 required by Taiwan NCC and Israel. ID 0~999 is allocated by GSMA */
-    public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_919
-            = 0x0397; // 919
-
-    /** Channel 928 required by Israel. ID 0~999 is allocated by GSMA */
-    public static final int MESSAGE_ID_GSMA_ALLOCATED_CHANNEL_928
-            = 0x03A0; // 928
-
     /** Start of PWS Message Identifier range (includes ETWS and CMAS). */
     public static final int MESSAGE_ID_PWS_FIRST_IDENTIFIER
             = 0x1100; // 4352
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index b550cfa..00bf33a 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -689,8 +689,20 @@
         AudioFormat format =  event.getCaptureAudioFormat();
         result = result + "AudioFormat: " + ((format == null) ? "null" : format.toString());
         byte[] triggerAudio = event.getTriggerAudio();
-        result = result + "TriggerAudio: " + (triggerAudio == null ? "null" : triggerAudio.length);
-        result = result + "CaptureSession: " + event.getCaptureSession();
+        result = result + ", TriggerAudio: " + (triggerAudio == null ? "null" : triggerAudio.length);
+        byte[] data = event.getData();
+        result = result + ", Data: " + (data == null ? "null" : data.length);
+        if (data != null) {
+          try {
+            String decodedData = new String(data, "UTF-8");
+            if (decodedData.chars().allMatch(c -> (c >= 32 && c < 128) || c == 0)) {
+                result = result + ", Decoded Data: '" + decodedData + "'";
+            }
+          } catch (Exception e) {
+            Log.e(TAG, "Failed to decode data");
+          }
+        }
+        result = result + ", CaptureSession: " + event.getCaptureSession();
         result += " )";
         return result;
     }
diff --git a/tests/SurfaceComposition/Android.mk b/tests/SurfaceComposition/Android.mk
index 95f69f1..d97c3f4 100644
--- a/tests/SurfaceComposition/Android.mk
+++ b/tests/SurfaceComposition/Android.mk
@@ -27,6 +27,8 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
+LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test junit
+
 LOCAL_PACKAGE_NAME := SurfaceComposition
 
 LOCAL_SDK_VERSION := current
diff --git a/tests/WindowAnimationJank/Android.mk b/tests/WindowAnimationJank/Android.mk
index 888ae64..f356afb 100644
--- a/tests/WindowAnimationJank/Android.mk
+++ b/tests/WindowAnimationJank/Android.mk
@@ -24,7 +24,11 @@
 
 LOCAL_PACKAGE_NAME := WindowAnimationJank
 
-LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator ub-janktesthelper
+LOCAL_STATIC_JAVA_LIBRARIES := \
+    ub-uiautomator \
+    ub-janktesthelper \
+    legacy-android-test \
+    junit
 
 LOCAL_SDK_VERSION := current
 
diff --git a/tests/net/Android.mk b/tests/net/Android.mk
index 504d54e..3af0adc 100644
--- a/tests/net/Android.mk
+++ b/tests/net/Android.mk
@@ -52,7 +52,6 @@
     libtinyxml2 \
     libvintf \
     libhwbinder \
-    android.hidl.base@1.0 \
     android.hidl.token@1.0
 
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/tests/radio/src/android/hardware/radio/tests/RadioTest.java b/tests/radio/src/android/hardware/radio/tests/RadioTest.java
index 7ab5618..fd69383 100644
--- a/tests/radio/src/android/hardware/radio/tests/RadioTest.java
+++ b/tests/radio/src/android/hardware/radio/tests/RadioTest.java
@@ -42,6 +42,7 @@
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 
 /**
  * A test for broadcast radio API.
@@ -52,6 +53,7 @@
     public final Context mContext = InstrumentationRegistry.getContext();
 
     private final int kConfigCallbacktimeoutNs = 10000;
+    private final int kTuneCallbacktimeoutNs = 30000;
 
     private RadioManager mRadioManager;
     private RadioTuner mRadioTuner;
@@ -89,9 +91,19 @@
             mRadioTuner.close();
             mRadioTuner = null;
         }
+        verifyNoMoreInteractions(mCallback);
     }
 
     private void openTuner() {
+        openTuner(true);
+    }
+
+    private void resetCallback() {
+        verifyNoMoreInteractions(mCallback);
+        Mockito.reset(mCallback);
+    }
+
+    private void openTuner(boolean withAudio) {
         assertNull(mRadioTuner);
 
         // find FM band and build its config
@@ -109,17 +121,16 @@
         mAmBandConfig = new RadioManager.AmBandConfig.Builder(mAmBandDescriptor).build();
         mFmBandConfig = new RadioManager.FmBandConfig.Builder(mFmBandDescriptor).build();
 
-        mRadioTuner = mRadioManager.openTuner(module.getId(), mFmBandConfig, true, mCallback, null);
+        mRadioTuner = mRadioManager.openTuner(module.getId(),
+                mFmBandConfig, withAudio, mCallback, null);
         assertNotNull(mRadioTuner);
         verify(mCallback, timeout(kConfigCallbacktimeoutNs).times(1)).onConfigurationChanged(any());
-        verify(mCallback, never()).onError(anyInt());
-        Mockito.reset(mCallback);
+        resetCallback();
     }
 
     @Test
     public void testOpenTuner() {
         openTuner();
-        verify(mCallback, never()).onError(anyInt());
     }
 
     @Test
@@ -129,7 +140,6 @@
         mRadioTuner = null;
         Thread.sleep(100);  // TODO(b/36122635): force reopen
         openTuner();
-        verify(mCallback, never()).onError(anyInt());
     }
 
     @Test
@@ -146,7 +156,6 @@
         ret = mRadioTuner.getConfiguration(config);
         assertEquals(RadioManager.STATUS_OK, ret);
 
-        verify(mCallback, never()).onError(anyInt());
         assertEquals(mAmBandConfig, config[0]);
     }
 
@@ -175,7 +184,49 @@
         ret = mRadioTuner.setConfiguration(mAmBandConfig);
         assertEquals(RadioManager.STATUS_OK, ret);
         verify(mCallback, timeout(kConfigCallbacktimeoutNs).times(1)).onConfigurationChanged(any());
+    }
 
-        verify(mCallback, never()).onError(anyInt());
+    @Test
+    public void testMute() {
+        openTuner();
+
+        boolean isMuted = mRadioTuner.getMute();
+        assertFalse(isMuted);
+
+        int ret = mRadioTuner.setMute(true);
+        assertEquals(RadioManager.STATUS_OK, ret);
+        isMuted = mRadioTuner.getMute();
+        assertTrue(isMuted);
+
+        ret = mRadioTuner.setMute(false);
+        assertEquals(RadioManager.STATUS_OK, ret);
+        isMuted = mRadioTuner.getMute();
+        assertFalse(isMuted);
+    }
+
+    @Test
+    public void testMuteNoAudio() {
+        openTuner(false);
+
+        int ret = mRadioTuner.setMute(false);
+        assertEquals(RadioManager.STATUS_ERROR, ret);
+
+        boolean isMuted = mRadioTuner.getMute();
+        assertTrue(isMuted);
+    }
+
+    @Test
+    public void testStep() {
+        openTuner();
+
+        int ret = mRadioTuner.step(RadioTuner.DIRECTION_DOWN, true);
+        assertEquals(RadioManager.STATUS_OK, ret);
+        verify(mCallback, timeout(kTuneCallbacktimeoutNs).times(1)).onProgramInfoChanged(any());
+
+        resetCallback();
+
+        ret = mRadioTuner.step(RadioTuner.DIRECTION_UP, false);
+        assertEquals(RadioManager.STATUS_OK, ret);
+        verify(mCallback, timeout(kTuneCallbacktimeoutNs).times(1)).onProgramInfoChanged(any());
     }
 }
diff --git a/tests/testables/src/android/testing/AndroidTestingRunner.java b/tests/testables/src/android/testing/AndroidTestingRunner.java
index a425f70..cf5d4cf 100644
--- a/tests/testables/src/android/testing/AndroidTestingRunner.java
+++ b/tests/testables/src/android/testing/AndroidTestingRunner.java
@@ -35,6 +35,8 @@
 
 /**
  * A runner with support for extra annotations provided by the Testables library.
+ * @see UiThreadTest
+ * @see TestableLooper.RunWithLooper
  */
 public class AndroidTestingRunner extends BlockJUnit4ClassRunner {
 
diff --git a/tests/testables/src/android/testing/BaseFragmentTest.java b/tests/testables/src/android/testing/BaseFragmentTest.java
index 32ee091..5cedbdf 100644
--- a/tests/testables/src/android/testing/BaseFragmentTest.java
+++ b/tests/testables/src/android/testing/BaseFragmentTest.java
@@ -80,6 +80,10 @@
         });
     }
 
+    /**
+     * Allows tests to sub-class TestableContext if they want to provide any extended functionality
+     * or provide a {@link LeakCheck} to the TestableContext upon instantiation.
+     */
     protected TestableContext getContext() {
         return new TestableContext(InstrumentationRegistry.getContext());
     }
diff --git a/tests/testables/src/android/testing/LeakCheck.java b/tests/testables/src/android/testing/LeakCheck.java
index 8daaa8f..949215b 100644
--- a/tests/testables/src/android/testing/LeakCheck.java
+++ b/tests/testables/src/android/testing/LeakCheck.java
@@ -14,6 +14,7 @@
 
 package android.testing;
 
+import android.content.Context;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -28,6 +29,35 @@
 import java.util.List;
 import java.util.Map;
 
+/**
+ * Utility for dealing with the facts of Lifecycle. Creates trackers to check that for every
+ * call to registerX, addX, bindX, a corresponding call to unregisterX, removeX, and unbindX
+ * is performed. This should be applied to a test as a {@link org.junit.rules.TestRule}
+ * and will only check for leaks on successful tests.
+ * <p>
+ * Example that will catch an allocation and fail:
+ * <pre class="prettyprint">
+ * public class LeakCheckTest {
+ *    &#064;Rule public LeakCheck mLeakChecker = new LeakCheck();
+ *
+ *    &#064;Test
+ *    public void testLeak() {
+ *        Context context = new ContextWrapper(...) {
+ *            public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
+ *                mLeakChecker.getTracker("receivers").addAllocation(new Throwable());
+ *            }
+ *            public void unregisterReceiver(BroadcastReceiver receiver) {
+ *                mLeakChecker.getTracker("receivers").clearAllocations();
+ *            }
+ *        };
+ *        context.registerReceiver(...);
+ *    }
+ *  }
+ * </pre>
+ *
+ * Note: {@link TestableContext} supports leak tracking when using
+ * {@link TestableContext#TestableContext(Context, LeakCheck)}.
+ */
 public class LeakCheck extends TestWatcher {
 
     private final Map<String, Tracker> mTrackers = new HashMap<>();
@@ -40,6 +70,13 @@
         verify();
     }
 
+    /**
+     * Acquire a {@link Tracker}. Gets a tracker for the specified tag, creating one if necessary.
+     * There should be one tracker for each pair of add/remove callbacks (e.g. one tracker for
+     * registerReceiver/unregisterReceiver).
+     *
+     * @param tag Unique tag to use for this set of allocation tracking.
+     */
     public Tracker getTracker(String tag) {
         Tracker t = mTrackers.get(tag);
         if (t == null) {
@@ -49,10 +86,13 @@
         return t;
     }
 
-    public void verify() {
+    private void verify() {
         mTrackers.values().forEach(Tracker::verify);
     }
 
+    /**
+     * Holds allocations associated with a specific callback (such as a BroadcastReceiver).
+     */
     public static class LeakInfo {
         private static final String TAG = "LeakInfo";
         private List<Throwable> mThrowables = new ArrayList<>();
@@ -60,11 +100,20 @@
         LeakInfo() {
         }
 
+        /**
+         * Should be called once for each callback/listener added. addAllocation may be
+         * called several times, but it only takes one clearAllocations call to remove all
+         * of them.
+         */
         public void addAllocation(Throwable t) {
             // TODO: Drop off the first element in the stack trace here to have a cleaner stack.
             mThrowables.add(t);
         }
 
+        /**
+         * Should be called when the callback/listener has been removed. One call to
+         * clearAllocations will counteract any number of calls to addAllocation.
+         */
         public void clearAllocations() {
             mThrowables.clear();
         }
@@ -82,9 +131,16 @@
         }
     }
 
+    /**
+     * Tracks allocations related to a specific tag or method(s).
+     * @see #getTracker(String)
+     */
     public static class Tracker {
         private Map<Object, LeakInfo> mObjects = new ArrayMap<>();
 
+        private Tracker() {
+        }
+
         public LeakInfo getLeakInfo(Object object) {
             LeakInfo leakInfo = mObjects.get(object);
             if (leakInfo == null) {
diff --git a/tests/testables/src/android/testing/TestableContentResolver.java b/tests/testables/src/android/testing/TestableContentResolver.java
index bfafbe0..0850916 100644
--- a/tests/testables/src/android/testing/TestableContentResolver.java
+++ b/tests/testables/src/android/testing/TestableContentResolver.java
@@ -27,7 +27,11 @@
 import java.util.Map;
 
 /**
- * Alternative to a MockContentResolver that falls back to real providers.
+ * A version of ContentResolver that allows easy mocking of providers.
+ * By default it acts as a normal ContentResolver and returns all the
+ * same providers.
+ * @see #addProvider(String, ContentProvider)
+ * @see #setFallbackToExisting(boolean)
  */
 public class TestableContentResolver extends ContentResolver {
 
diff --git a/tests/testables/src/android/testing/TestableContext.java b/tests/testables/src/android/testing/TestableContext.java
index d6c06e4..498d517 100644
--- a/tests/testables/src/android/testing/TestableContext.java
+++ b/tests/testables/src/android/testing/TestableContext.java
@@ -43,6 +43,7 @@
  * <ul>
  * <li>System services can be mocked out with {@link #addMockSystemService}</li>
  * <li>Service binding can be mocked out with {@link #addMockService}</li>
+ * <li>Resources can be mocked out using {@link #getOrCreateTestableResources()}</li>
  * <li>Settings support {@link TestableSettingsProvider}</li>
  * <li>Has support for {@link LeakCheck} for services and receivers</li>
  * </ul>
@@ -50,10 +51,8 @@
  * <p>TestableContext should be defined as a rule on your test so it can clean up after itself.
  * Like the following:</p>
  * <pre class="prettyprint">
- * {@literal
- * @Rule
+ * &#064;Rule
  * private final TestableContext mContext = new TestableContext(InstrumentationRegister.getContext());
- * }
  * </pre>
  */
 public class TestableContext extends ContextWrapper implements TestRule {
@@ -132,20 +131,26 @@
                 : super.getResources();
     }
 
+    /**
+     * @see #getSystemService(String)
+     */
     public <T> void addMockSystemService(Class<T> service, T mock) {
         addMockSystemService(getSystemServiceName(service), mock);
     }
 
+    /**
+     * @see #getSystemService(String)
+     */
     public void addMockSystemService(String name, Object service) {
         if (mMockSystemServices == null) mMockSystemServices = new ArrayMap<>();
         mMockSystemServices.put(name, service);
     }
 
-    public void addMockService(ComponentName component, IBinder service) {
-        if (mMockServices == null) mMockServices = new ArrayMap<>();
-        mMockServices.put(component, service);
-    }
-
+    /**
+     * If a matching mock service has been added through {@link #addMockSystemService} then
+     * that will be returned, otherwise the real service will be acquired from the base
+     * context.
+     */
     @Override
     public Object getSystemService(String name) {
         if (mMockSystemServices != null && mMockSystemServices.containsKey(name)) {
@@ -166,6 +171,10 @@
         return mTestableContentResolver;
     }
 
+    /**
+     * Will always return itself for a TestableContext to ensure the testable effects extend
+     * to the application context.
+     */
     @Override
     public Context getApplicationContext() {
         // Return this so its always a TestableContext.
@@ -199,6 +208,24 @@
         super.unregisterReceiver(receiver);
     }
 
+    /**
+     * Adds a mock service to be connected to by a bindService call.
+     * <p>
+     *     Normally a TestableContext will pass through all bind requests to the base context
+     *     but when addMockService has been called for a ComponentName being bound, then
+     *     TestableContext will immediately trigger a {@link ServiceConnection#onServiceConnected}
+     *     with the specified service, and will call {@link ServiceConnection#onServiceDisconnected}
+     *     when the service is unbound.
+     * </p>
+     */
+    public void addMockService(ComponentName component, IBinder service) {
+        if (mMockServices == null) mMockServices = new ArrayMap<>();
+        mMockServices.put(component, service);
+    }
+
+    /**
+     * @see #addMockService(ComponentName, IBinder)
+     */
     @Override
     public boolean bindService(Intent service, ServiceConnection conn, int flags) {
         if (mService != null) mService.getLeakInfo(conn).addAllocation(new Throwable());
@@ -206,6 +233,9 @@
         return super.bindService(service, conn, flags);
     }
 
+    /**
+     * @see #addMockService(ComponentName, IBinder)
+     */
     @Override
     public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
             Handler handler, UserHandle user) {
@@ -214,6 +244,9 @@
         return super.bindServiceAsUser(service, conn, flags, handler, user);
     }
 
+    /**
+     * @see #addMockService(ComponentName, IBinder)
+     */
     @Override
     public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
             UserHandle user) {
@@ -232,6 +265,9 @@
         return false;
     }
 
+    /**
+     * @see #addMockService(ComponentName, IBinder)
+     */
     @Override
     public void unbindService(ServiceConnection conn) {
         if (mService != null) mService.getLeakInfo(conn).clearAllocations();
@@ -243,6 +279,13 @@
         super.unbindService(conn);
     }
 
+    /**
+     * Check if the TestableContext has a mock binding for a specified component. Will return
+     * true between {@link ServiceConnection#onServiceConnected} and
+     * {@link ServiceConnection#onServiceDisconnected} callbacks for a mock service.
+     *
+     * @see #addMockService(ComponentName, IBinder)
+     */
     public boolean isBound(ComponentName component) {
         return mActiveServices != null && mActiveServices.containsValue(component);
     }
diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java
index 9eddc51..f6c3cb3 100644
--- a/tests/testables/src/android/testing/TestableLooper.java
+++ b/tests/testables/src/android/testing/TestableLooper.java
@@ -33,16 +33,15 @@
 import java.util.Map;
 
 /**
- * Creates a looper on the current thread with control over if/when messages are
- * executed. Warning: This class works through some reflection and may break/need
- * to be updated from time to time.
+ * This is a wrapper around {@link TestLooperManager} to make it easier to manage
+ * and provide an easy annotation for use with tests.
+ *
+ * @see TestableLooperTest TestableLooperTest for examples.
  */
 public class TestableLooper {
 
     private Looper mLooper;
     private MessageQueue mQueue;
-    private boolean mMain;
-    private Object mOriginalMain;
     private MessageHandler mMessageHandler;
 
     private Handler mHandler;
@@ -72,35 +71,20 @@
         mHandler = new Handler(mLooper);
     }
 
-    public void setAsMainLooper() throws NoSuchFieldException, IllegalAccessException {
-        mMain = true;
-        setAsMainInt();
-    }
-
-    private void setAsMainInt() throws NoSuchFieldException, IllegalAccessException {
-        Field field = mLooper.getClass().getDeclaredField("sMainLooper");
-        field.setAccessible(true);
-        if (mOriginalMain == null) {
-            mOriginalMain = field.get(null);
-        }
-        field.set(null, mLooper);
-    }
-
     /**
-     * Must be called if setAsMainLooper is called to restore the main looper when the
-     * test is complete, otherwise the main looper will not be available for any subsequent
-     * tests.
+     * Must be called to release the looper when the test is complete, otherwise
+     * the looper will not be available for any subsequent tests. This is
+     * automatically handled for tests using {@link RunWithLooper}.
      */
     public void destroy() throws NoSuchFieldException, IllegalAccessException {
         mQueueWrapper.release();
-        if (mMain && mOriginalMain != null) {
-            Field field = mLooper.getClass().getDeclaredField("sMainLooper");
-            field.setAccessible(true);
-            field.set(null, mOriginalMain);
-            mOriginalMain = null;
-        }
     }
 
+    /**
+     * Sets a callback for all messages processed on this TestableLooper.
+     *
+     * @see {@link MessageHandler}
+     */
     public void setMessageHandler(MessageHandler handler) {
         mMessageHandler = handler;
     }
@@ -119,6 +103,9 @@
         return num;
     }
 
+    /**
+     * Process messages in the queue until no more are found.
+     */
     public void processAllMessages() {
         while (processQueuedMessages() != 0) ;
     }
@@ -183,6 +170,11 @@
         void run() throws Exception;
     }
 
+    /**
+     * Annotation that tells the {@link AndroidTestingRunner} to create a TestableLooper and
+     * run this test/class on that thread. The {@link TestableLooper} can be acquired using
+     * {@link #get(Object)}.
+     */
     @Retention(RetentionPolicy.RUNTIME)
     @Target({ElementType.METHOD, ElementType.TYPE})
     public @interface RunWithLooper {
@@ -206,11 +198,15 @@
 
     private static final Map<Object, TestableLooper> sLoopers = new ArrayMap<>();
 
+    /**
+     * For use with {@link RunWithLooper}, used to get the TestableLooper that was
+     * automatically created for this test.
+     */
     public static TestableLooper get(Object test) {
         return sLoopers.get(test);
     }
 
-    public static class LooperFrameworkMethod extends FrameworkMethod {
+    static class LooperFrameworkMethod extends FrameworkMethod {
         private HandlerThread mHandlerThread;
 
         private final TestableLooper mTestableLooper;
@@ -319,6 +315,11 @@
         }
     }
 
+    /**
+     * Callback to control the execution of messages on the looper, when set with
+     * {@link #setMessageHandler(MessageHandler)} then {@link #onMessageHandled(Message)}
+     * will get called back for every message processed on the {@link TestableLooper}.
+     */
     public interface MessageHandler {
         /**
          * Return true to have the message executed and delivered to target.
diff --git a/tests/testables/src/android/testing/UiThreadTest.java b/tests/testables/src/android/testing/UiThreadTest.java
index e40e1d7..32a5824 100644
--- a/tests/testables/src/android/testing/UiThreadTest.java
+++ b/tests/testables/src/android/testing/UiThreadTest.java
@@ -20,8 +20,8 @@
 import java.lang.annotation.Target;
 
 /**
- * When applied to a class, all tests, befores, and afters will behave as if
- * they have @UiThreadTest applied to them.
+ * When applied to a class, all {@link org.junit.Test}s, {@link org.junit.After}s, and
+ * {@link org.junit.Before} will behave as if they have @UiThreadTest applied to them.
  */
 @Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
diff --git a/tests/testables/src/android/testing/ViewUtils.java b/tests/testables/src/android/testing/ViewUtils.java
index 5a651aa..7478998 100644
--- a/tests/testables/src/android/testing/ViewUtils.java
+++ b/tests/testables/src/android/testing/ViewUtils.java
@@ -21,8 +21,16 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 
+/**
+ * Utilities to make testing views easier.
+ */
 public class ViewUtils {
 
+    /**
+     * Causes the view (and its children) to have {@link View#onAttachedToWindow()} called.
+     *
+     * This is currently done by adding the view to a window.
+     */
     public static void attachView(View view) {
         // Make sure hardware acceleration isn't turned on.
         view.getContext().getApplicationInfo().flags &=
@@ -35,6 +43,11 @@
                 .getSystemService(WindowManager.class).addView(view, lp);
     }
 
+    /**
+     * Causes the view (and its children) to have {@link View#onDetachedFromWindow()} called.
+     *
+     * This is currently done by removing the view from a window.
+     */
     public static void detachView(View view) {
         InstrumentationRegistry.getContext()
                 .getSystemService(WindowManager.class).removeViewImmediate(view);
diff --git a/tests/testables/tests/Android.mk b/tests/testables/tests/Android.mk
index a123d80..16fe535 100644
--- a/tests/testables/tests/Android.mk
+++ b/tests/testables/tests/Android.mk
@@ -18,7 +18,7 @@
 LOCAL_USE_AAPT2 := true
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_PACKAGE_NAME := TestablesTest
+LOCAL_PACKAGE_NAME := TestablesTests
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src) \
     $(call all-Iaidl-files-under, src)
diff --git a/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java b/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
index 8ae212c..0866577 100644
--- a/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
+++ b/tools/layoutlib/bridge/src/android/view/RectShadowPainter.java
@@ -18,13 +18,28 @@
 
 import android.annotation.NonNull;
 import android.graphics.Canvas;
+import android.graphics.LinearGradient;
 import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.Path.FillType;
+import android.graphics.RadialGradient;
 import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Shader.TileMode;
+
+import com.android.layoutlib.bridge.impl.ResourceHelper;
 import com.android.layoutlib.bridge.shadowutil.SpotShadow;
 import com.android.layoutlib.bridge.shadowutil.ShadowBuffer;
 
 public class RectShadowPainter {
 
+    private static final float SIMPLE_SHADOW_ELEVATION_THRESHOLD = 16f;
+    private static final int SIMPLE_SHADOW_START_COLOR = ResourceHelper.getColor("#37000000");
+    private static final int SIMPLE_SHADOW_END_COLOR = ResourceHelper.getColor("#03000000");
+    private static final float PERPENDICULAR_ANGLE = 90f;
+
     private static final float SHADOW_STRENGTH = 0.1f;
     private static final int LIGHT_POINTS = 8;
 
@@ -41,6 +56,11 @@
             return;
         }
 
+        if (elevation <= 0) {
+            // If elevation is 0, we don't need to paint the shadow
+            return;
+        }
+
         Rect originCanvasRect = canvas.getClipBounds();
         int saved = modifyCanvas(canvas);
         if (saved == -1) {
@@ -53,23 +73,30 @@
                 return;
             }
 
-            // view's absolute position in this canvas.
-            int viewLeft = -originCanvasRect.left + outline.left;
-            int viewTop = -originCanvasRect.top + outline.top;
-            int viewRight = viewLeft + outline.width();
-            int viewBottom = viewTop + outline.height();
+            if (elevation <= SIMPLE_SHADOW_ELEVATION_THRESHOLD) {
+                // When elevation is not high, the shadow is very similar to a small outline of
+                // View. For the performance reason, we draw the shadow in simple way.
+                simpleRectangleShadow(canvas, outline, radius, elevation);
+            } else {
+                // view's absolute position in this canvas.
+                int viewLeft = -originCanvasRect.left + outline.left;
+                int viewTop = -originCanvasRect.top + outline.top;
+                int viewRight = viewLeft + outline.width();
+                int viewBottom = viewTop + outline.height();
 
-            float[][] rectangleCoordinators = generateRectangleCoordinates(viewLeft, viewTop,
-                    viewRight, viewBottom, radius, elevation);
+                float[][] rectangleCoordinators =
+                        generateRectangleCoordinates(viewLeft, viewTop, viewRight, viewBottom,
+                                radius, elevation);
 
-            // TODO: get these values from resources.
-            float lightPosX = canvas.getWidth() / 2;
-            float lightPosY = 0;
-            float lightHeight = 1800;
-            float lightSize = 200;
+                // TODO: get these values from resources.
+                float lightPosX = canvas.getWidth() / 2;
+                float lightPosY = 0;
+                float lightHeight = 1800;
+                float lightSize = 200;
 
-            paintGeometricShadow(rectangleCoordinators, lightPosX, lightPosY, lightHeight,
-                    lightSize, canvas);
+                paintGeometricShadow(rectangleCoordinators, lightPosX, lightPosY, lightHeight,
+                        lightSize, canvas);
+            }
         } finally {
             canvas.restoreToCount(saved);
         }
@@ -81,6 +108,94 @@
         return canvas.save();
     }
 
+    private static void simpleRectangleShadow(@NonNull Canvas canvas, @NonNull Rect outline,
+            float radius, float elevation) {
+        float shadowSize = elevation / 2;
+
+        Paint cornerPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
+        cornerPaint.setStyle(Style.FILL);
+        Paint edgePaint = new Paint(cornerPaint);
+        edgePaint.setAntiAlias(false);
+        float outerArcRadius = radius + shadowSize;
+        int[] colors = {SIMPLE_SHADOW_START_COLOR, SIMPLE_SHADOW_START_COLOR,
+                SIMPLE_SHADOW_END_COLOR};
+        cornerPaint.setShader(new RadialGradient(0, 0, outerArcRadius, colors,
+                new float[]{0f, radius / outerArcRadius, 1f}, TileMode.CLAMP));
+        edgePaint.setShader(new LinearGradient(0, 0, -shadowSize, 0, SIMPLE_SHADOW_START_COLOR,
+                SIMPLE_SHADOW_END_COLOR,
+                TileMode.CLAMP));
+        Path path = new Path();
+        path.setFillType(FillType.EVEN_ODD);
+        // A rectangle bounding the complete shadow.
+        RectF shadowRect = new RectF(outline);
+        shadowRect.inset(-shadowSize, -shadowSize);
+        // A rectangle with edges corresponding to the straight edges of the outline.
+        RectF inset = new RectF(outline);
+        inset.inset(radius, radius);
+        // A rectangle used to represent the edge shadow.
+        RectF edgeShadowRect = new RectF();
+
+
+        // left and right sides.
+        edgeShadowRect.set(-shadowSize, 0f, 0f, inset.height());
+        // Left shadow
+        drawSideShadow(canvas, edgePaint, edgeShadowRect, outline.left, inset.top, 0);
+        // Right shadow
+        drawSideShadow(canvas, edgePaint, edgeShadowRect, outline.right, inset.bottom, 2);
+        // Top shadow
+        edgeShadowRect.set(-shadowSize, 0, 0, inset.width());
+        drawSideShadow(canvas, edgePaint, edgeShadowRect, inset.right, outline.top, 1);
+        // bottom shadow. This needs an inset so that blank doesn't appear when the content is
+        // moved up.
+        edgeShadowRect.set(-shadowSize, 0, shadowSize / 2f, inset.width());
+        edgePaint.setShader(
+                new LinearGradient(edgeShadowRect.right, 0, edgeShadowRect.left, 0, colors,
+                        new float[]{0f, 1 / 3f, 1f}, TileMode.CLAMP));
+        drawSideShadow(canvas, edgePaint, edgeShadowRect, inset.left, outline.bottom, 3);
+
+        // Draw corners.
+        drawCorner(canvas, cornerPaint, path, inset.right, inset.bottom, outerArcRadius, 0);
+        drawCorner(canvas, cornerPaint, path, inset.left, inset.bottom, outerArcRadius, 1);
+        drawCorner(canvas, cornerPaint, path, inset.left, inset.top, outerArcRadius, 2);
+        drawCorner(canvas, cornerPaint, path, inset.right, inset.top, outerArcRadius, 3);
+    }
+
+    private static void drawSideShadow(@NonNull Canvas canvas, @NonNull Paint edgePaint,
+            @NonNull RectF shadowRect, float dx, float dy, int rotations) {
+        if ((int) shadowRect.left >= (int) shadowRect.right ||
+                (int) shadowRect.top >= (int) shadowRect.bottom) {
+            // Rect is empty, no need to draw shadow
+            return;
+        }
+        int saved = canvas.save();
+        canvas.translate(dx, dy);
+        canvas.rotate(rotations * PERPENDICULAR_ANGLE);
+        canvas.drawRect(shadowRect, edgePaint);
+        canvas.restoreToCount(saved);
+    }
+
+    /**
+     * @param canvas Canvas to draw the rectangle on.
+     * @param paint Paint to use when drawing the corner.
+     * @param path A path to reuse. Prevents allocating memory for each path.
+     * @param x Center of circle, which this corner is a part of.
+     * @param y Center of circle, which this corner is a part of.
+     * @param radius radius of the arc
+     * @param rotations number of quarter rotations before starting to paint the arc.
+     */
+    private static void drawCorner(@NonNull Canvas canvas, @NonNull Paint paint, @NonNull Path path,
+            float x, float y, float radius, int rotations) {
+        int saved = canvas.save();
+        canvas.translate(x, y);
+        path.reset();
+        path.arcTo(-radius, -radius, radius, radius, rotations * PERPENDICULAR_ANGLE,
+                PERPENDICULAR_ANGLE, false);
+        path.lineTo(0, 0);
+        path.close();
+        canvas.drawPath(path, paint);
+        canvas.restoreToCount(saved);
+    }
+
     @NonNull
     private static float[][] generateRectangleCoordinates(float left, float top, float right,
             float bottom, float radius, float elevation) {
diff --git a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
index 23caaf8..4b760a7 100644
--- a/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/ViewGroup_Delegate.java
@@ -50,12 +50,14 @@
             // the outline obtained is correct.
             child.setBackgroundBounds();
             ViewOutlineProvider outlineProvider = child.getOutlineProvider();
-            Outline outline = child.mAttachInfo.mTmpOutline;
-            outlineProvider.getOutline(child, outline);
-            if (outline.mPath != null || (outline.mRect != null && !outline.mRect.isEmpty())) {
-                int restoreTo = transformCanvas(thisVG, canvas, child);
-                drawShadow(thisVG, canvas, child, outline);
-                canvas.restoreToCount(restoreTo);
+            if (outlineProvider != null) {
+                Outline outline = child.mAttachInfo.mTmpOutline;
+                outlineProvider.getOutline(child, outline);
+                if (outline.mPath != null || (outline.mRect != null && !outline.mRect.isEmpty())) {
+                    int restoreTo = transformCanvas(thisVG, canvas, child);
+                    drawShadow(thisVG, canvas, child, outline);
+                    canvas.restoreToCount(restoreTo);
+                }
             }
         }
         return thisVG.drawChild_Original(canvas, child, drawingTime);
diff --git a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
index 67355b8..4951629 100644
--- a/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
+++ b/tools/layoutlib/bridge/tests/res/testApp/MyApplication/golden/shadows_test.png
Binary files differ
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index e31a74b..f7333e2 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -839,6 +839,10 @@
          */
         public static final int NETWORK_SELECTION_ENABLE = 0;
         /**
+         * The starting index for network selection disabled reasons
+         */
+        public static final int NETWORK_SELECTION_DISABLED_STARTING_INDEX = 1;
+        /**
          * @deprecated it is not used any more.
          * This network is disabled because higher layer (>2) network is bad
          */
diff --git a/wifi/tests/src/android/net/wifi/WifiManagerTest.java b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
index 03ef319..adf897d 100644
--- a/wifi/tests/src/android/net/wifi/WifiManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiManagerTest.java
@@ -22,6 +22,7 @@
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_GENERIC;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_INCOMPATIBLE_MODE;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_NO_CHANNEL;
+import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.ERROR_TETHERING_DISALLOWED;
 import static android.net.wifi.WifiManager.LocalOnlyHotspotCallback.REQUEST_REGISTERED;
 
 import static org.junit.Assert.assertEquals;
@@ -335,14 +336,13 @@
      */
     @Test
     public void testCorrectLooperIsUsedForHandler() throws Exception {
-        // record thread from looper.getThread and check ids.
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)))
                 .thenReturn(ERROR_INCOMPATIBLE_MODE);
         mWifiManager.startLocalOnlyHotspot(callback, mHandler);
         mLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
-        assertEquals(mLooper.getLooper().getThread().getId(), callback.mCallingThreadId);
+        verify(mContext, never()).getMainLooper();
     }
 
     /**
@@ -361,6 +361,7 @@
         altLooper.dispatchAll();
         assertEquals(ERROR_INCOMPATIBLE_MODE, callback.mFailureReason);
         assertEquals(altLooper.getLooper().getThread().getId(), callback.mCallingThreadId);
+        verify(mContext).getMainLooper();
     }
 
     /**
@@ -464,11 +465,10 @@
     }
 
     /**
-     * Verify the handler passed in to startLocalOnlyHotspot is correctly used for callbacks when a
-     * null WifiConfig is returned.
+     * Verify callback triggered from startLocalOnlyHotspot with an incompatible mode failure.
      */
     @Test
-    public void testLocalOnlyHotspotCallbackFullOnNullConfig() throws Exception {
+    public void testLocalOnlyHotspotCallbackFullOnIncompatibleMode() throws Exception {
         TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
         when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)))
                 .thenReturn(ERROR_INCOMPATIBLE_MODE);
@@ -481,6 +481,22 @@
     }
 
     /**
+     * Verify callback triggered from startLocalOnlyHotspot with a tethering disallowed failure.
+     */
+    @Test
+    public void testLocalOnlyHotspotCallbackFullOnTetheringDisallowed() throws Exception {
+        TestLocalOnlyHotspotCallback callback = new TestLocalOnlyHotspotCallback();
+        when(mWifiService.startLocalOnlyHotspot(any(Messenger.class), any(IBinder.class)))
+                .thenReturn(ERROR_TETHERING_DISALLOWED);
+        mWifiManager.startLocalOnlyHotspot(callback, mHandler);
+        mLooper.dispatchAll();
+        assertEquals(ERROR_TETHERING_DISALLOWED, callback.mFailureReason);
+        assertFalse(callback.mOnStartedCalled);
+        assertFalse(callback.mOnStoppedCalled);
+        assertEquals(null, callback.mRes);
+    }
+
+    /**
      * Verify a SecurityException resulting from an application without necessary permissions will
      * bubble up through the call to start LocalOnlyHotspot and will not trigger other callbacks.
      */
@@ -616,12 +632,11 @@
      */
     @Test
     public void testCorrectLooperIsUsedForObserverHandler() throws Exception {
-        // record thread from looper.getThread and check ids.
         TestLocalOnlyHotspotObserver observer = new TestLocalOnlyHotspotObserver();
         mWifiManager.watchLocalOnlyHotspot(observer, mHandler);
         mLooper.dispatchAll();
         assertTrue(observer.mOnRegistered);
-        assertEquals(mLooper.getLooper().getThread().getId(), observer.mCallingThreadId);
+        verify(mContext, never()).getMainLooper();
     }
 
     /**
@@ -638,6 +653,7 @@
         altLooper.dispatchAll();
         assertTrue(observer.mOnRegistered);
         assertEquals(altLooper.getLooper().getThread().getId(), observer.mCallingThreadId);
+        verify(mContext).getMainLooper();
     }
 
     /**