Merge "Store pending OTA state and make it accessible via polling api."
diff --git a/Android.bp b/Android.bp
index 9088315..81d6dab 100644
--- a/Android.bp
+++ b/Android.bp
@@ -14,6 +14,7 @@
 
 subdirs = [
     "libs/*",
+    "tools/*",
     "native/android",
     "native/graphics/jni",
 ]
diff --git a/Android.mk b/Android.mk
index 8e8b95a..21bd76b 100644
--- a/Android.mk
+++ b/Android.mk
@@ -178,8 +178,6 @@
 	core/java/android/hardware/display/IDisplayManager.aidl \
 	core/java/android/hardware/display/IDisplayManagerCallback.aidl \
 	core/java/android/hardware/display/IVirtualDisplayCallback.aidl \
-	core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl \
-	core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintService.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintServiceLockoutResetCallback.aidl \
 	core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl \
diff --git a/api/current.txt b/api/current.txt
index dfb3302..0cb0296c 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -989,6 +989,7 @@
     field public static final int preferenceStyle = 16842894; // 0x101008e
     field public static final int presentationTheme = 16843712; // 0x10103c0
     field public static final int previewImage = 16843482; // 0x10102da
+    field public static final int primaryContentAlpha = 16843367; // 0x1010267
     field public static final int priority = 16842780; // 0x101001c
     field public static final int privateImeOptions = 16843299; // 0x1010223
     field public static final int process = 16842769; // 0x1010011
@@ -4591,6 +4592,7 @@
 
   public abstract class FragmentContainer {
     ctor public FragmentContainer();
+    method public android.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
     method public abstract android.view.View onFindViewById(int);
     method public abstract boolean onHasView();
   }
@@ -5025,6 +5027,7 @@
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
     field public static final int DEFAULT_SOUND = 1; // 0x1
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
     field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
     field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
@@ -5108,6 +5111,7 @@
     method public android.app.Notification.Action clone();
     method public int describeContents();
     method public boolean getAllowGeneratedReplies();
+    method public android.app.RemoteInput[] getDataOnlyRemoteInputs();
     method public android.os.Bundle getExtras();
     method public android.graphics.drawable.Icon getIcon();
     method public android.app.RemoteInput[] getRemoteInputs();
@@ -5573,14 +5577,18 @@
   }
 
   public final class RemoteInput implements android.os.Parcelable {
+    method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
     method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
     method public int describeContents();
     method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String> getAllowedDataTypes();
     method public java.lang.CharSequence[] getChoices();
+    method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
     method public android.os.Bundle getExtras();
     method public java.lang.CharSequence getLabel();
     method public java.lang.String getResultKey();
     method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public boolean isDataOnly();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
     field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
@@ -5592,6 +5600,7 @@
     method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
     method public android.app.RemoteInput build();
     method public android.os.Bundle getExtras();
+    method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
     method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
     method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
     method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
@@ -8216,12 +8225,15 @@
     field public static final java.lang.String EXTRA_SIZE = "android.content.extra.SIZE";
     field public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 2; // 0x2
     field public static final int NOTIFY_SYNC_TO_NETWORK = 1; // 0x1
+    field public static final java.lang.String QUERY_ARG_LIMIT = "android:query-page-limit";
+    field public static final java.lang.String QUERY_ARG_OFFSET = "android:query-page-offset";
     field public static final java.lang.String QUERY_ARG_SORT_COLLATION = "android:query-sort-collation";
     field public static final java.lang.String QUERY_ARG_SORT_COLUMNS = "android:query-sort-columns";
     field public static final java.lang.String QUERY_ARG_SORT_DIRECTION = "android:query-sort-direction";
     field public static final java.lang.String QUERY_ARG_SQL_SELECTION = "android:query-sql-selection";
     field public static final java.lang.String QUERY_ARG_SQL_SELECTION_ARGS = "android:query-sql-selection-args";
     field public static final java.lang.String QUERY_ARG_SQL_SORT_ORDER = "android:query-sql-sort-order";
+    field public static final java.lang.String QUERY_RESULT_SIZE = "android:query-result-size";
     field public static final int QUERY_SORT_DIRECTION_ASCENDING = 0; // 0x0
     field public static final int QUERY_SORT_DIRECTION_DESCENDING = 1; // 0x1
     field public static final java.lang.String SCHEME_ANDROID_RESOURCE = "android.resource";
@@ -9004,10 +9016,10 @@
     field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
     field public static final java.lang.String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
     field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
-    field public static final java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
-    field public static final java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
@@ -9792,6 +9804,8 @@
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.content.IntentSender getShortcutConfigActivityIntent(android.content.pm.LauncherActivityInfo);
+    method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(java.lang.String, android.os.UserHandle);
     method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
     method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
     method public boolean hasShortcutHostPermission();
@@ -10395,6 +10409,7 @@
 
   public class ShortcutManager {
     method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public android.content.Intent createShortcutResultIntent(android.content.pm.ShortcutInfo);
     method public void disableShortcuts(java.util.List<java.lang.String>);
     method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.CharSequence);
     method public void enableShortcuts(java.util.List<java.lang.String>);
@@ -12126,15 +12141,57 @@
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
     method public static void RGBToHSV(int, int, int, float[]);
+    method public float alpha();
+    method public static float alpha(long);
     method public static int alpha(int);
     method public static int argb(int, int, int, int);
+    method public static int argb(float, float, float, float);
+    method public float blue();
+    method public static float blue(long);
     method public static int blue(int);
+    method public static android.graphics.ColorSpace colorSpace(long);
     method public static void colorToHSV(int, float[]);
+    method public android.graphics.Color convert(android.graphics.ColorSpace);
+    method public static long convert(int, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace.Connector);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace.Connector);
+    method public android.graphics.ColorSpace getColorSpace();
+    method public float getComponent(int);
+    method public int getComponentCount();
+    method public float[] getComponents();
+    method public android.graphics.ColorSpace.Model getModel();
+    method public float green();
+    method public static float green(long);
     method public static int green(int);
+    method public static boolean isInColorSpace(long, android.graphics.ColorSpace);
+    method public boolean isSrgb();
+    method public static boolean isSrgb(long);
+    method public boolean isWideGamut();
+    method public static boolean isWideGamut(long);
+    method public float luminance();
+    method public static float luminance(long);
     method public static float luminance(int);
+    method public long pack();
+    method public static long pack(int);
+    method public static long pack(float, float, float);
+    method public static long pack(float, float, float, float);
+    method public static long pack(float, float, float, float, android.graphics.ColorSpace);
     method public static int parseColor(java.lang.String);
+    method public float red();
+    method public static float red(long);
     method public static int red(int);
     method public static int rgb(int, int, int);
+    method public static int rgb(float, float, float);
+    method public int toArgb();
+    method public static int toArgb(long);
+    method public static android.graphics.Color valueOf(int);
+    method public static android.graphics.Color valueOf(long);
+    method public static android.graphics.Color valueOf(float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float, android.graphics.ColorSpace);
+    method public static android.graphics.Color valueOf(float[], android.graphics.ColorSpace);
     field public static final int BLACK = -16777216; // 0xff000000
     field public static final int BLUE = -16776961; // 0xff0000ff
     field public static final int CYAN = -16711681; // 0xff00ffff
@@ -12206,7 +12263,7 @@
     field public static final float[] ILLUMINANT_D65;
     field public static final float[] ILLUMINANT_D75;
     field public static final float[] ILLUMINANT_E;
-    field public static final int MAX_ID = 64; // 0x40
+    field public static final int MAX_ID = 63; // 0x3f
     field public static final int MIN_ID = -1; // 0xffffffff
   }
 
@@ -25002,7 +25059,9 @@
   public class WifiConfiguration implements android.os.Parcelable {
     ctor public WifiConfiguration();
     method public int describeContents();
+    method public android.net.ProxyInfo getHttpProxy();
     method public boolean isPasspoint();
+    method public void setHttpProxy(android.net.ProxyInfo);
     method public void writeToParcel(android.os.Parcel, int);
     field public java.lang.String BSSID;
     field public java.lang.String FQDN;
@@ -29849,6 +29908,15 @@
     field public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8; // 0xfffffff8
   }
 
+  public abstract class ProxyFileDescriptorCallback {
+    ctor public ProxyFileDescriptorCallback();
+    method public void onFsync() throws android.system.ErrnoException;
+    method public long onGetSize() throws android.system.ErrnoException;
+    method public int onRead(long, int, byte[]) throws android.system.ErrnoException;
+    method public abstract void onRelease();
+    method public int onWrite(long, int, byte[]) throws android.system.ErrnoException;
+  }
+
   public class RecoverySystem {
     method public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException;
     method public static void rebootWipeCache(android.content.Context) throws java.io.IOException;
@@ -30266,6 +30334,7 @@
     method public boolean isEncrypted(java.io.File);
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
+    method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
     field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
   }
@@ -32363,7 +32432,7 @@
     ctor public ContactsContract.Intents();
     field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+    field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -32473,8 +32542,10 @@
   public static final class ContactsContract.ProviderStatus {
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
     field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     field public static final java.lang.String STATUS = "status";
     field public static final int STATUS_BUSY = 1; // 0x1
+    field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
     field public static final int STATUS_EMPTY = 2; // 0x2
     field public static final int STATUS_NORMAL = 0; // 0x0
   }
@@ -32620,6 +32691,7 @@
     method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
     method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
+    method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
     method public static java.util.List<java.lang.String> findDocumentPath(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
@@ -32664,6 +32736,7 @@
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
     field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+    field public static final int FLAG_WEB_LINKABLE = 4096; // 0x1000
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
@@ -32697,6 +32770,7 @@
     ctor public DocumentsProvider();
     method public java.lang.String copyDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+    method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
     method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
@@ -35208,6 +35282,7 @@
     field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
     field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+    field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
   }
 
   public final class FillCallback {
@@ -35413,7 +35488,6 @@
     field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
     field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-    field public static final java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
   }
 
   public class MediaBrowserService.Result<T> {
@@ -45110,6 +45184,7 @@
     method public int getDrawingOrder();
     method public java.lang.CharSequence getError();
     method public android.os.Bundle getExtras();
+    method public java.lang.CharSequence getHintText();
     method public int getInputType();
     method public android.view.accessibility.AccessibilityNodeInfo getLabelFor();
     method public android.view.accessibility.AccessibilityNodeInfo getLabeledBy();
@@ -45144,6 +45219,7 @@
     method public boolean isPassword();
     method public boolean isScrollable();
     method public boolean isSelected();
+    method public boolean isShowingHintText();
     method public boolean isVisibleToUser();
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
@@ -45177,6 +45253,7 @@
     method public void setError(java.lang.CharSequence);
     method public void setFocusable(boolean);
     method public void setFocused(boolean);
+    method public void setHintText(java.lang.CharSequence);
     method public void setImportantForAccessibility(boolean);
     method public void setInputType(int);
     method public void setLabelFor(android.view.View);
@@ -45195,6 +45272,7 @@
     method public void setRangeInfo(android.view.accessibility.AccessibilityNodeInfo.RangeInfo);
     method public void setScrollable(boolean);
     method public void setSelected(boolean);
+    method public void setShowingHintText(boolean);
     method public void setSource(android.view.View);
     method public void setSource(android.view.View, int);
     method public void setText(java.lang.CharSequence);
@@ -53119,6 +53197,133 @@
 
 }
 
+package java.lang.invoke {
+
+  public class LambdaConversionException extends java.lang.Exception {
+    ctor public LambdaConversionException();
+    ctor public LambdaConversionException(java.lang.String);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable, boolean, boolean);
+  }
+
+  public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asFixedArity();
+    method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
+    method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
+    method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
+    method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
+    method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+    method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
+    method public boolean isVarargsCollector();
+    method public java.lang.invoke.MethodType type();
+  }
+
+  public abstract interface MethodHandleInfo {
+    method public abstract java.lang.Class<?> getDeclaringClass();
+    method public abstract java.lang.invoke.MethodType getMethodType();
+    method public abstract int getModifiers();
+    method public abstract java.lang.String getName();
+    method public abstract int getReferenceKind();
+    method public default boolean isVarArgs();
+    method public static boolean refKindIsField(int);
+    method public static boolean refKindIsValid(int);
+    method public static java.lang.String refKindName(int);
+    method public static java.lang.String referenceKindToString(int);
+    method public abstract <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandles.Lookup);
+    method public static java.lang.String toString(int, java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType);
+    field public static final int REF_getField = 1; // 0x1
+    field public static final int REF_getStatic = 2; // 0x2
+    field public static final int REF_invokeInterface = 9; // 0x9
+    field public static final int REF_invokeSpecial = 7; // 0x7
+    field public static final int REF_invokeStatic = 6; // 0x6
+    field public static final int REF_invokeVirtual = 5; // 0x5
+    field public static final int REF_newInvokeSpecial = 8; // 0x8
+    field public static final int REF_putField = 3; // 0x3
+    field public static final int REF_putStatic = 4; // 0x4
+  }
+
+  public class MethodHandles {
+    method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
+    method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
+    method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
+    method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
+    method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandles.Lookup lookup();
+    method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
+    method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+    method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
+  }
+
+  public static final class MethodHandles.Lookup {
+    method public java.lang.invoke.MethodHandle bind(java.lang.Object, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findConstructor(java.lang.Class<?>, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSpecial(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStatic(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStaticGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findStaticSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
+    method public java.lang.Class<?> lookupClass();
+    method public int lookupModes();
+    method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSpecial(java.lang.reflect.Method, java.lang.Class<?>) throws java.lang.IllegalAccessException;
+    field public static final int PACKAGE = 8; // 0x8
+    field public static final int PRIVATE = 2; // 0x2
+    field public static final int PROTECTED = 4; // 0x4
+    field public static final int PUBLIC = 1; // 0x1
+  }
+
+  public final class MethodType implements java.io.Serializable {
+    method public java.lang.invoke.MethodType appendParameterTypes(java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType appendParameterTypes(java.util.List<java.lang.Class<?>>);
+    method public java.lang.invoke.MethodType changeParameterType(int, java.lang.Class<?>);
+    method public java.lang.invoke.MethodType changeReturnType(java.lang.Class<?>);
+    method public java.lang.invoke.MethodType dropParameterTypes(int, int);
+    method public java.lang.invoke.MethodType erase();
+    method public static java.lang.invoke.MethodType fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) throws java.lang.IllegalArgumentException, java.lang.TypeNotPresentException;
+    method public java.lang.invoke.MethodType generic();
+    method public static java.lang.invoke.MethodType genericMethodType(int, boolean);
+    method public static java.lang.invoke.MethodType genericMethodType(int);
+    method public boolean hasPrimitives();
+    method public boolean hasWrappers();
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>[]);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>, java.lang.Class<?>...);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.invoke.MethodType);
+    method public java.lang.Class<?>[] parameterArray();
+    method public int parameterCount();
+    method public java.util.List<java.lang.Class<?>> parameterList();
+    method public java.lang.Class<?> parameterType(int);
+    method public java.lang.Class<?> returnType();
+    method public java.lang.String toMethodDescriptorString();
+    method public java.lang.invoke.MethodType unwrap();
+    method public java.lang.invoke.MethodType wrap();
+  }
+
+  public class WrongMethodTypeException extends java.lang.RuntimeException {
+    ctor public WrongMethodTypeException();
+    ctor public WrongMethodTypeException(java.lang.String);
+  }
+
+}
+
 package java.lang.ref {
 
   public class PhantomReference<T> extends java.lang.ref.Reference {
@@ -55844,8 +56049,10 @@
   public final class FileTime implements java.lang.Comparable {
     method public int compareTo(java.nio.file.attribute.FileTime);
     method public static java.nio.file.attribute.FileTime from(long, java.util.concurrent.TimeUnit);
+    method public static java.nio.file.attribute.FileTime from(java.time.Instant);
     method public static java.nio.file.attribute.FileTime fromMillis(long);
     method public long to(java.util.concurrent.TimeUnit);
+    method public java.time.Instant toInstant();
     method public long toMillis();
   }
 
@@ -61502,6 +61709,7 @@
     method public boolean before(java.util.Date);
     method public java.lang.Object clone();
     method public int compareTo(java.util.Date);
+    method public static java.util.Date from(java.time.Instant);
     method public deprecated int getDate();
     method public deprecated int getDay();
     method public deprecated int getHours();
@@ -61520,6 +61728,7 @@
     method public void setTime(long);
     method public deprecated void setYear(int);
     method public deprecated java.lang.String toGMTString();
+    method public java.time.Instant toInstant();
     method public deprecated java.lang.String toLocaleString();
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index dfe57d87..a059436 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1098,6 +1098,7 @@
     field public static final int preferenceStyle = 16842894; // 0x101008e
     field public static final int presentationTheme = 16843712; // 0x10103c0
     field public static final int previewImage = 16843482; // 0x10102da
+    field public static final int primaryContentAlpha = 16843367; // 0x1010267
     field public static final int priority = 16842780; // 0x101001c
     field public static final int privateImeOptions = 16843299; // 0x1010223
     field public static final int process = 16842769; // 0x1010011
@@ -4748,6 +4749,7 @@
 
   public abstract class FragmentContainer {
     ctor public FragmentContainer();
+    method public android.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
     method public abstract android.view.View onFindViewById(int);
     method public abstract boolean onHasView();
   }
@@ -5183,6 +5185,7 @@
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
     field public static final int DEFAULT_SOUND = 1; // 0x1
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
     field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
     field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
@@ -5268,6 +5271,7 @@
     method public android.app.Notification.Action clone();
     method public int describeContents();
     method public boolean getAllowGeneratedReplies();
+    method public android.app.RemoteInput[] getDataOnlyRemoteInputs();
     method public android.os.Bundle getExtras();
     method public android.graphics.drawable.Icon getIcon();
     method public android.app.RemoteInput[] getRemoteInputs();
@@ -5484,6 +5488,17 @@
     field protected android.app.Notification.Builder mBuilder;
   }
 
+  public static final class Notification.TvExtender implements android.app.Notification.Extender {
+    ctor public Notification.TvExtender();
+    ctor public Notification.TvExtender(android.app.Notification);
+    method public android.app.Notification.Builder extend(android.app.Notification.Builder);
+    method public android.app.PendingIntent getContentIntent();
+    method public android.app.PendingIntent getDeleteIntent();
+    method public boolean isAvailableOnTv();
+    method public android.app.Notification.TvExtender setContentIntent(android.app.PendingIntent);
+    method public android.app.Notification.TvExtender setDeleteIntent(android.app.PendingIntent);
+  }
+
   public static final class Notification.WearableExtender implements android.app.Notification.Extender {
     ctor public Notification.WearableExtender();
     ctor public Notification.WearableExtender(android.app.Notification);
@@ -5747,14 +5762,18 @@
   }
 
   public final class RemoteInput implements android.os.Parcelable {
+    method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
     method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
     method public int describeContents();
     method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String> getAllowedDataTypes();
     method public java.lang.CharSequence[] getChoices();
+    method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
     method public android.os.Bundle getExtras();
     method public java.lang.CharSequence getLabel();
     method public java.lang.String getResultKey();
     method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public boolean isDataOnly();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
     field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
@@ -5766,6 +5785,7 @@
     method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
     method public android.app.RemoteInput build();
     method public android.os.Bundle getExtras();
+    method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
     method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
     method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
     method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
@@ -8566,12 +8586,15 @@
     field public static final java.lang.String EXTRA_SIZE = "android.content.extra.SIZE";
     field public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 2; // 0x2
     field public static final int NOTIFY_SYNC_TO_NETWORK = 1; // 0x1
+    field public static final java.lang.String QUERY_ARG_LIMIT = "android:query-page-limit";
+    field public static final java.lang.String QUERY_ARG_OFFSET = "android:query-page-offset";
     field public static final java.lang.String QUERY_ARG_SORT_COLLATION = "android:query-sort-collation";
     field public static final java.lang.String QUERY_ARG_SORT_COLUMNS = "android:query-sort-columns";
     field public static final java.lang.String QUERY_ARG_SORT_DIRECTION = "android:query-sort-direction";
     field public static final java.lang.String QUERY_ARG_SQL_SELECTION = "android:query-sql-selection";
     field public static final java.lang.String QUERY_ARG_SQL_SELECTION_ARGS = "android:query-sql-selection-args";
     field public static final java.lang.String QUERY_ARG_SQL_SORT_ORDER = "android:query-sql-sort-order";
+    field public static final java.lang.String QUERY_RESULT_SIZE = "android:query-result-size";
     field public static final int QUERY_SORT_DIRECTION_ASCENDING = 0; // 0x0
     field public static final int QUERY_SORT_DIRECTION_DESCENDING = 1; // 0x1
     field public static final java.lang.String SCHEME_ANDROID_RESOURCE = "android.resource";
@@ -9386,10 +9409,10 @@
     field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
     field public static final java.lang.String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
     field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
-    field public static final java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
-    field public static final java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final java.lang.String EXTRA_SPLIT_NAME = "android.intent.extra.SPLIT_NAME";
     field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
@@ -10209,6 +10232,8 @@
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.content.IntentSender getShortcutConfigActivityIntent(android.content.pm.LauncherActivityInfo);
+    method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(java.lang.String, android.os.UserHandle);
     method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
     method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
     method public boolean hasShortcutHostPermission();
@@ -10885,6 +10910,7 @@
 
   public class ShortcutManager {
     method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public android.content.Intent createShortcutResultIntent(android.content.pm.ShortcutInfo);
     method public void disableShortcuts(java.util.List<java.lang.String>);
     method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.CharSequence);
     method public void enableShortcuts(java.util.List<java.lang.String>);
@@ -12630,15 +12656,57 @@
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
     method public static void RGBToHSV(int, int, int, float[]);
+    method public float alpha();
+    method public static float alpha(long);
     method public static int alpha(int);
     method public static int argb(int, int, int, int);
+    method public static int argb(float, float, float, float);
+    method public float blue();
+    method public static float blue(long);
     method public static int blue(int);
+    method public static android.graphics.ColorSpace colorSpace(long);
     method public static void colorToHSV(int, float[]);
+    method public android.graphics.Color convert(android.graphics.ColorSpace);
+    method public static long convert(int, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace.Connector);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace.Connector);
+    method public android.graphics.ColorSpace getColorSpace();
+    method public float getComponent(int);
+    method public int getComponentCount();
+    method public float[] getComponents();
+    method public android.graphics.ColorSpace.Model getModel();
+    method public float green();
+    method public static float green(long);
     method public static int green(int);
+    method public static boolean isInColorSpace(long, android.graphics.ColorSpace);
+    method public boolean isSrgb();
+    method public static boolean isSrgb(long);
+    method public boolean isWideGamut();
+    method public static boolean isWideGamut(long);
+    method public float luminance();
+    method public static float luminance(long);
     method public static float luminance(int);
+    method public long pack();
+    method public static long pack(int);
+    method public static long pack(float, float, float);
+    method public static long pack(float, float, float, float);
+    method public static long pack(float, float, float, float, android.graphics.ColorSpace);
     method public static int parseColor(java.lang.String);
+    method public float red();
+    method public static float red(long);
     method public static int red(int);
     method public static int rgb(int, int, int);
+    method public static int rgb(float, float, float);
+    method public int toArgb();
+    method public static int toArgb(long);
+    method public static android.graphics.Color valueOf(int);
+    method public static android.graphics.Color valueOf(long);
+    method public static android.graphics.Color valueOf(float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float, android.graphics.ColorSpace);
+    method public static android.graphics.Color valueOf(float[], android.graphics.ColorSpace);
     field public static final int BLACK = -16777216; // 0xff000000
     field public static final int BLUE = -16776961; // 0xff0000ff
     field public static final int CYAN = -16711681; // 0xff00ffff
@@ -12710,7 +12778,7 @@
     field public static final float[] ILLUMINANT_D65;
     field public static final float[] ILLUMINANT_D75;
     field public static final float[] ILLUMINANT_E;
-    field public static final int MAX_ID = 64; // 0x40
+    field public static final int MAX_ID = 63; // 0x3f
     field public static final int MIN_ID = -1; // 0xffffffff
   }
 
@@ -21859,6 +21927,7 @@
     method public int getClientPid();
     method public int getClientUid();
     method public int getPlayerInterfaceId();
+    method public android.media.PlayerProxy getPlayerProxy();
     method public int getPlayerState();
     method public int getPlayerType();
     method public void writeToParcel(android.os.Parcel, int);
@@ -23687,6 +23756,13 @@
     field public static final android.os.Parcelable.Creator<android.media.PlaybackParams> CREATOR;
   }
 
+  public class PlayerProxy {
+    method public void pause() throws java.lang.IllegalStateException;
+    method public void setVolume(float) throws java.lang.IllegalStateException;
+    method public void start() throws java.lang.IllegalStateException;
+    method public void stop() throws java.lang.IllegalStateException;
+  }
+
   public final class Rating implements android.os.Parcelable {
     method public int describeContents();
     method public float getPercentRating();
@@ -27353,9 +27429,11 @@
   public class WifiConfiguration implements android.os.Parcelable {
     ctor public WifiConfiguration();
     method public int describeContents();
+    method public android.net.ProxyInfo getHttpProxy();
     method public boolean hasNoInternetAccess();
     method public boolean isNoInternetAccessExpected();
     method public boolean isPasspoint();
+    method public void setHttpProxy(android.net.ProxyInfo);
     method public void writeToParcel(android.os.Parcel, int);
     field public java.lang.String BSSID;
     field public java.lang.String FQDN;
@@ -32451,6 +32529,15 @@
     field public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8; // 0xfffffff8
   }
 
+  public abstract class ProxyFileDescriptorCallback {
+    ctor public ProxyFileDescriptorCallback();
+    method public void onFsync() throws android.system.ErrnoException;
+    method public long onGetSize() throws android.system.ErrnoException;
+    method public int onRead(long, int, byte[]) throws android.system.ErrnoException;
+    method public abstract void onRelease();
+    method public int onWrite(long, int, byte[]) throws android.system.ErrnoException;
+  }
+
   public class RecoverySystem {
     method public static void cancelScheduledUpdate(android.content.Context) throws java.io.IOException;
     method public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException;
@@ -32698,7 +32785,8 @@
     method public android.os.UserHandle getUserForSerialNumber(long);
     method public java.lang.String getUserName();
     method public java.util.List<android.os.UserHandle> getUserProfiles();
-    method public int getUserRestrictionSource(java.lang.String, android.os.UserHandle);
+    method public deprecated int getUserRestrictionSource(java.lang.String, android.os.UserHandle);
+    method public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(java.lang.String, android.os.UserHandle);
     method public android.os.Bundle getUserRestrictions();
     method public android.os.Bundle getUserRestrictions(android.os.UserHandle);
     method public boolean hasUserRestriction(java.lang.String);
@@ -32764,6 +32852,14 @@
     field public static final int USER_CREATION_FAILED_NO_MORE_USERS = 2; // 0x2
   }
 
+  public static final class UserManager.EnforcingUser implements android.os.Parcelable {
+    method public int describeContents();
+    method public android.os.UserHandle getUserHandle();
+    method public int getUserRestrictionSource();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.UserManager.EnforcingUser> CREATOR;
+  }
+
   public static abstract class UserManager.UserRestrictionSource implements java.lang.annotation.Annotation {
   }
 
@@ -32954,6 +33050,7 @@
     method public boolean isEncrypted(java.io.File);
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
+    method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
     field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
   }
@@ -35090,7 +35187,7 @@
     ctor public ContactsContract.Intents();
     field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+    field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -35230,8 +35327,10 @@
   public static final class ContactsContract.ProviderStatus {
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
     field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     field public static final java.lang.String STATUS = "status";
     field public static final int STATUS_BUSY = 1; // 0x1
+    field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
     field public static final int STATUS_EMPTY = 2; // 0x2
     field public static final int STATUS_NORMAL = 0; // 0x0
   }
@@ -35377,6 +35476,7 @@
     method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
     method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
+    method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
     method public static java.util.List<java.lang.String> findDocumentPath(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
@@ -35421,6 +35521,7 @@
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
     field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+    field public static final int FLAG_WEB_LINKABLE = 4096; // 0x1000
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
@@ -35454,6 +35555,7 @@
     ctor public DocumentsProvider();
     method public java.lang.String copyDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+    method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
     method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
@@ -38079,6 +38181,7 @@
     field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
     field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+    field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
   }
 
   public final class FillCallback {
@@ -38284,7 +38387,6 @@
     field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
     field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-    field public static final java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
   }
 
   public class MediaBrowserService.Result<T> {
@@ -48341,6 +48443,7 @@
     method public int getDrawingOrder();
     method public java.lang.CharSequence getError();
     method public android.os.Bundle getExtras();
+    method public java.lang.CharSequence getHintText();
     method public int getInputType();
     method public android.view.accessibility.AccessibilityNodeInfo getLabelFor();
     method public android.view.accessibility.AccessibilityNodeInfo getLabeledBy();
@@ -48375,6 +48478,7 @@
     method public boolean isPassword();
     method public boolean isScrollable();
     method public boolean isSelected();
+    method public boolean isShowingHintText();
     method public boolean isVisibleToUser();
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
@@ -48408,6 +48512,7 @@
     method public void setError(java.lang.CharSequence);
     method public void setFocusable(boolean);
     method public void setFocused(boolean);
+    method public void setHintText(java.lang.CharSequence);
     method public void setImportantForAccessibility(boolean);
     method public void setInputType(int);
     method public void setLabelFor(android.view.View);
@@ -48426,6 +48531,7 @@
     method public void setRangeInfo(android.view.accessibility.AccessibilityNodeInfo.RangeInfo);
     method public void setScrollable(boolean);
     method public void setSelected(boolean);
+    method public void setShowingHintText(boolean);
     method public void setSource(android.view.View);
     method public void setSource(android.view.View, int);
     method public void setText(java.lang.CharSequence);
@@ -56707,6 +56813,133 @@
 
 }
 
+package java.lang.invoke {
+
+  public class LambdaConversionException extends java.lang.Exception {
+    ctor public LambdaConversionException();
+    ctor public LambdaConversionException(java.lang.String);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable, boolean, boolean);
+  }
+
+  public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asFixedArity();
+    method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
+    method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
+    method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
+    method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
+    method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+    method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
+    method public boolean isVarargsCollector();
+    method public java.lang.invoke.MethodType type();
+  }
+
+  public abstract interface MethodHandleInfo {
+    method public abstract java.lang.Class<?> getDeclaringClass();
+    method public abstract java.lang.invoke.MethodType getMethodType();
+    method public abstract int getModifiers();
+    method public abstract java.lang.String getName();
+    method public abstract int getReferenceKind();
+    method public default boolean isVarArgs();
+    method public static boolean refKindIsField(int);
+    method public static boolean refKindIsValid(int);
+    method public static java.lang.String refKindName(int);
+    method public static java.lang.String referenceKindToString(int);
+    method public abstract <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandles.Lookup);
+    method public static java.lang.String toString(int, java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType);
+    field public static final int REF_getField = 1; // 0x1
+    field public static final int REF_getStatic = 2; // 0x2
+    field public static final int REF_invokeInterface = 9; // 0x9
+    field public static final int REF_invokeSpecial = 7; // 0x7
+    field public static final int REF_invokeStatic = 6; // 0x6
+    field public static final int REF_invokeVirtual = 5; // 0x5
+    field public static final int REF_newInvokeSpecial = 8; // 0x8
+    field public static final int REF_putField = 3; // 0x3
+    field public static final int REF_putStatic = 4; // 0x4
+  }
+
+  public class MethodHandles {
+    method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
+    method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
+    method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
+    method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
+    method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandles.Lookup lookup();
+    method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
+    method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+    method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
+  }
+
+  public static final class MethodHandles.Lookup {
+    method public java.lang.invoke.MethodHandle bind(java.lang.Object, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findConstructor(java.lang.Class<?>, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSpecial(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStatic(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStaticGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findStaticSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
+    method public java.lang.Class<?> lookupClass();
+    method public int lookupModes();
+    method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSpecial(java.lang.reflect.Method, java.lang.Class<?>) throws java.lang.IllegalAccessException;
+    field public static final int PACKAGE = 8; // 0x8
+    field public static final int PRIVATE = 2; // 0x2
+    field public static final int PROTECTED = 4; // 0x4
+    field public static final int PUBLIC = 1; // 0x1
+  }
+
+  public final class MethodType implements java.io.Serializable {
+    method public java.lang.invoke.MethodType appendParameterTypes(java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType appendParameterTypes(java.util.List<java.lang.Class<?>>);
+    method public java.lang.invoke.MethodType changeParameterType(int, java.lang.Class<?>);
+    method public java.lang.invoke.MethodType changeReturnType(java.lang.Class<?>);
+    method public java.lang.invoke.MethodType dropParameterTypes(int, int);
+    method public java.lang.invoke.MethodType erase();
+    method public static java.lang.invoke.MethodType fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) throws java.lang.IllegalArgumentException, java.lang.TypeNotPresentException;
+    method public java.lang.invoke.MethodType generic();
+    method public static java.lang.invoke.MethodType genericMethodType(int, boolean);
+    method public static java.lang.invoke.MethodType genericMethodType(int);
+    method public boolean hasPrimitives();
+    method public boolean hasWrappers();
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>[]);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>, java.lang.Class<?>...);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.invoke.MethodType);
+    method public java.lang.Class<?>[] parameterArray();
+    method public int parameterCount();
+    method public java.util.List<java.lang.Class<?>> parameterList();
+    method public java.lang.Class<?> parameterType(int);
+    method public java.lang.Class<?> returnType();
+    method public java.lang.String toMethodDescriptorString();
+    method public java.lang.invoke.MethodType unwrap();
+    method public java.lang.invoke.MethodType wrap();
+  }
+
+  public class WrongMethodTypeException extends java.lang.RuntimeException {
+    ctor public WrongMethodTypeException();
+    ctor public WrongMethodTypeException(java.lang.String);
+  }
+
+}
+
 package java.lang.ref {
 
   public class PhantomReference<T> extends java.lang.ref.Reference {
@@ -59432,8 +59665,10 @@
   public final class FileTime implements java.lang.Comparable {
     method public int compareTo(java.nio.file.attribute.FileTime);
     method public static java.nio.file.attribute.FileTime from(long, java.util.concurrent.TimeUnit);
+    method public static java.nio.file.attribute.FileTime from(java.time.Instant);
     method public static java.nio.file.attribute.FileTime fromMillis(long);
     method public long to(java.util.concurrent.TimeUnit);
+    method public java.time.Instant toInstant();
     method public long toMillis();
   }
 
@@ -65090,6 +65325,7 @@
     method public boolean before(java.util.Date);
     method public java.lang.Object clone();
     method public int compareTo(java.util.Date);
+    method public static java.util.Date from(java.time.Instant);
     method public deprecated int getDate();
     method public deprecated int getDay();
     method public deprecated int getHours();
@@ -65108,6 +65344,7 @@
     method public void setTime(long);
     method public deprecated void setYear(int);
     method public deprecated java.lang.String toGMTString();
+    method public java.time.Instant toInstant();
     method public deprecated java.lang.String toLocaleString();
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 189c6e2..9f56787 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -989,6 +989,7 @@
     field public static final int preferenceStyle = 16842894; // 0x101008e
     field public static final int presentationTheme = 16843712; // 0x10103c0
     field public static final int previewImage = 16843482; // 0x10102da
+    field public static final int primaryContentAlpha = 16843367; // 0x1010267
     field public static final int priority = 16842780; // 0x101001c
     field public static final int privateImeOptions = 16843299; // 0x1010223
     field public static final int process = 16842769; // 0x1010011
@@ -4601,6 +4602,7 @@
 
   public abstract class FragmentContainer {
     ctor public FragmentContainer();
+    method public android.app.Fragment instantiate(android.content.Context, java.lang.String, android.os.Bundle);
     method public abstract android.view.View onFindViewById(int);
     method public abstract boolean onHasView();
   }
@@ -5035,6 +5037,7 @@
     field public static final int DEFAULT_LIGHTS = 4; // 0x4
     field public static final int DEFAULT_SOUND = 1; // 0x1
     field public static final int DEFAULT_VIBRATE = 2; // 0x2
+    field public static final java.lang.String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
     field public static final java.lang.String EXTRA_BACKGROUND_IMAGE_URI = "android.backgroundImageUri";
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
     field public static final java.lang.String EXTRA_CHRONOMETER_COUNT_DOWN = "android.chronometerCountDown";
@@ -5118,6 +5121,7 @@
     method public android.app.Notification.Action clone();
     method public int describeContents();
     method public boolean getAllowGeneratedReplies();
+    method public android.app.RemoteInput[] getDataOnlyRemoteInputs();
     method public android.os.Bundle getExtras();
     method public android.graphics.drawable.Icon getIcon();
     method public android.app.RemoteInput[] getRemoteInputs();
@@ -5584,14 +5588,18 @@
   }
 
   public final class RemoteInput implements android.os.Parcelable {
+    method public static void addDataResultToIntent(android.app.RemoteInput, android.content.Intent, java.util.Map<java.lang.String, android.net.Uri>);
     method public static void addResultsToIntent(android.app.RemoteInput[], android.content.Intent, android.os.Bundle);
     method public int describeContents();
     method public boolean getAllowFreeFormInput();
+    method public java.util.Set<java.lang.String> getAllowedDataTypes();
     method public java.lang.CharSequence[] getChoices();
+    method public static java.util.Map<java.lang.String, android.net.Uri> getDataResultsFromIntent(android.content.Intent, java.lang.String);
     method public android.os.Bundle getExtras();
     method public java.lang.CharSequence getLabel();
     method public java.lang.String getResultKey();
     method public static android.os.Bundle getResultsFromIntent(android.content.Intent);
+    method public boolean isDataOnly();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.RemoteInput> CREATOR;
     field public static final java.lang.String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
@@ -5603,6 +5611,7 @@
     method public android.app.RemoteInput.Builder addExtras(android.os.Bundle);
     method public android.app.RemoteInput build();
     method public android.os.Bundle getExtras();
+    method public android.app.RemoteInput.Builder setAllowDataType(java.lang.String, boolean);
     method public android.app.RemoteInput.Builder setAllowFreeFormInput(boolean);
     method public android.app.RemoteInput.Builder setChoices(java.lang.CharSequence[]);
     method public android.app.RemoteInput.Builder setLabel(java.lang.CharSequence);
@@ -8239,12 +8248,15 @@
     field public static final java.lang.String EXTRA_SIZE = "android.content.extra.SIZE";
     field public static final int NOTIFY_SKIP_NOTIFY_FOR_DESCENDANTS = 2; // 0x2
     field public static final int NOTIFY_SYNC_TO_NETWORK = 1; // 0x1
+    field public static final java.lang.String QUERY_ARG_LIMIT = "android:query-page-limit";
+    field public static final java.lang.String QUERY_ARG_OFFSET = "android:query-page-offset";
     field public static final java.lang.String QUERY_ARG_SORT_COLLATION = "android:query-sort-collation";
     field public static final java.lang.String QUERY_ARG_SORT_COLUMNS = "android:query-sort-columns";
     field public static final java.lang.String QUERY_ARG_SORT_DIRECTION = "android:query-sort-direction";
     field public static final java.lang.String QUERY_ARG_SQL_SELECTION = "android:query-sql-selection";
     field public static final java.lang.String QUERY_ARG_SQL_SELECTION_ARGS = "android:query-sql-selection-args";
     field public static final java.lang.String QUERY_ARG_SQL_SORT_ORDER = "android:query-sql-sort-order";
+    field public static final java.lang.String QUERY_RESULT_SIZE = "android:query-result-size";
     field public static final int QUERY_SORT_DIRECTION_ASCENDING = 0; // 0x0
     field public static final int QUERY_SORT_DIRECTION_DESCENDING = 1; // 0x1
     field public static final java.lang.String SCHEME_ANDROID_RESOURCE = "android.resource";
@@ -9029,10 +9041,10 @@
     field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
     field public static final java.lang.String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
     field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
-    field public static final java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
-    field public static final java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
-    field public static final java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_ICON_RESOURCE = "android.intent.extra.shortcut.ICON_RESOURCE";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
+    field public static final deprecated java.lang.String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     field public static final java.lang.String EXTRA_SHUTDOWN_USERSPACE_ONLY = "android.intent.extra.SHUTDOWN_USERSPACE_ONLY";
     field public static final java.lang.String EXTRA_STREAM = "android.intent.extra.STREAM";
     field public static final java.lang.String EXTRA_SUBJECT = "android.intent.extra.SUBJECT";
@@ -9820,6 +9832,8 @@
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
+    method public android.content.IntentSender getShortcutConfigActivityIntent(android.content.pm.LauncherActivityInfo);
+    method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(java.lang.String, android.os.UserHandle);
     method public android.graphics.drawable.Drawable getShortcutIconDrawable(android.content.pm.ShortcutInfo, int);
     method public java.util.List<android.content.pm.ShortcutInfo> getShortcuts(android.content.pm.LauncherApps.ShortcutQuery, android.os.UserHandle);
     method public boolean hasShortcutHostPermission();
@@ -10427,6 +10441,7 @@
   public class ShortcutManager {
     ctor public ShortcutManager(android.content.Context);
     method public boolean addDynamicShortcuts(java.util.List<android.content.pm.ShortcutInfo>);
+    method public android.content.Intent createShortcutResultIntent(android.content.pm.ShortcutInfo);
     method public void disableShortcuts(java.util.List<java.lang.String>);
     method public void disableShortcuts(java.util.List<java.lang.String>, java.lang.CharSequence);
     method public void enableShortcuts(java.util.List<java.lang.String>);
@@ -12158,15 +12173,57 @@
     method public static int HSVToColor(float[]);
     method public static int HSVToColor(int, float[]);
     method public static void RGBToHSV(int, int, int, float[]);
+    method public float alpha();
+    method public static float alpha(long);
     method public static int alpha(int);
     method public static int argb(int, int, int, int);
+    method public static int argb(float, float, float, float);
+    method public float blue();
+    method public static float blue(long);
     method public static int blue(int);
+    method public static android.graphics.ColorSpace colorSpace(long);
     method public static void colorToHSV(int, float[]);
+    method public android.graphics.Color convert(android.graphics.ColorSpace);
+    method public static long convert(int, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace, android.graphics.ColorSpace);
+    method public static long convert(long, android.graphics.ColorSpace.Connector);
+    method public static long convert(float, float, float, float, android.graphics.ColorSpace.Connector);
+    method public android.graphics.ColorSpace getColorSpace();
+    method public float getComponent(int);
+    method public int getComponentCount();
+    method public float[] getComponents();
+    method public android.graphics.ColorSpace.Model getModel();
+    method public float green();
+    method public static float green(long);
     method public static int green(int);
+    method public static boolean isInColorSpace(long, android.graphics.ColorSpace);
+    method public boolean isSrgb();
+    method public static boolean isSrgb(long);
+    method public boolean isWideGamut();
+    method public static boolean isWideGamut(long);
+    method public float luminance();
+    method public static float luminance(long);
     method public static float luminance(int);
+    method public long pack();
+    method public static long pack(int);
+    method public static long pack(float, float, float);
+    method public static long pack(float, float, float, float);
+    method public static long pack(float, float, float, float, android.graphics.ColorSpace);
     method public static int parseColor(java.lang.String);
+    method public float red();
+    method public static float red(long);
     method public static int red(int);
     method public static int rgb(int, int, int);
+    method public static int rgb(float, float, float);
+    method public int toArgb();
+    method public static int toArgb(long);
+    method public static android.graphics.Color valueOf(int);
+    method public static android.graphics.Color valueOf(long);
+    method public static android.graphics.Color valueOf(float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float);
+    method public static android.graphics.Color valueOf(float, float, float, float, android.graphics.ColorSpace);
+    method public static android.graphics.Color valueOf(float[], android.graphics.ColorSpace);
     field public static final int BLACK = -16777216; // 0xff000000
     field public static final int BLUE = -16776961; // 0xff0000ff
     field public static final int CYAN = -16711681; // 0xff00ffff
@@ -12238,7 +12295,7 @@
     field public static final float[] ILLUMINANT_D65;
     field public static final float[] ILLUMINANT_D75;
     field public static final float[] ILLUMINANT_E;
-    field public static final int MAX_ID = 64; // 0x40
+    field public static final int MAX_ID = 63; // 0x3f
     field public static final int MIN_ID = -1; // 0xffffffff
   }
 
@@ -25090,7 +25147,9 @@
   public class WifiConfiguration implements android.os.Parcelable {
     ctor public WifiConfiguration();
     method public int describeContents();
+    method public android.net.ProxyInfo getHttpProxy();
     method public boolean isPasspoint();
+    method public void setHttpProxy(android.net.ProxyInfo);
     method public void writeToParcel(android.os.Parcel, int);
     field public java.lang.String BSSID;
     field public java.lang.String FQDN;
@@ -29959,6 +30018,15 @@
     field public static final int THREAD_PRIORITY_URGENT_DISPLAY = -8; // 0xfffffff8
   }
 
+  public abstract class ProxyFileDescriptorCallback {
+    ctor public ProxyFileDescriptorCallback();
+    method public void onFsync() throws android.system.ErrnoException;
+    method public long onGetSize() throws android.system.ErrnoException;
+    method public int onRead(long, int, byte[]) throws android.system.ErrnoException;
+    method public abstract void onRelease();
+    method public int onWrite(long, int, byte[]) throws android.system.ErrnoException;
+  }
+
   public class RecoverySystem {
     method public static void installPackage(android.content.Context, java.io.File) throws java.io.IOException;
     method public static void rebootWipeCache(android.content.Context) throws java.io.IOException;
@@ -30377,6 +30445,7 @@
     method public boolean isEncrypted(java.io.File);
     method public boolean isObbMounted(java.lang.String);
     method public boolean mountObb(java.lang.String, java.lang.String, android.os.storage.OnObbStateChangeListener);
+    method public android.os.ParcelFileDescriptor openProxyFileDescriptor(int, android.os.ProxyFileDescriptorCallback) throws java.io.IOException;
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
     field public static final java.lang.String ACTION_MANAGE_STORAGE = "android.os.storage.action.MANAGE_STORAGE";
   }
@@ -32477,7 +32546,7 @@
     ctor public ContactsContract.Intents();
     field public static final java.lang.String ACTION_VOICE_SEND_MESSAGE_TO_CONTACTS = "android.provider.action.VOICE_SEND_MESSAGE_TO_CONTACTS";
     field public static final java.lang.String ATTACH_IMAGE = "com.android.contacts.action.ATTACH_IMAGE";
-    field public static final java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
+    field public static final deprecated java.lang.String CONTACTS_DATABASE_CREATED = "android.provider.Contacts.DATABASE_CREATED";
     field public static final java.lang.String EXTRA_CREATE_DESCRIPTION = "com.android.contacts.action.CREATE_DESCRIPTION";
     field public static final java.lang.String EXTRA_FORCE_CREATE = "com.android.contacts.action.FORCE_CREATE";
     field public static final java.lang.String EXTRA_RECIPIENT_CONTACT_CHAT_ID = "android.provider.extra.RECIPIENT_CONTACT_CHAT_ID";
@@ -32587,8 +32656,10 @@
   public static final class ContactsContract.ProviderStatus {
     field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/provider_status";
     field public static final android.net.Uri CONTENT_URI;
+    field public static final java.lang.String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     field public static final java.lang.String STATUS = "status";
     field public static final int STATUS_BUSY = 1; // 0x1
+    field public static final android.net.Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI;
     field public static final int STATUS_EMPTY = 2; // 0x2
     field public static final int STATUS_NORMAL = 0; // 0x0
   }
@@ -32734,6 +32805,7 @@
     method public static android.net.Uri buildTreeDocumentUri(java.lang.String, java.lang.String);
     method public static android.net.Uri copyDocument(android.content.ContentResolver, android.net.Uri, android.net.Uri);
     method public static android.net.Uri createDocument(android.content.ContentResolver, android.net.Uri, java.lang.String, java.lang.String);
+    method public static android.content.IntentSender createWebLinkIntent(android.content.ContentResolver, android.net.Uri, android.os.Bundle);
     method public static boolean deleteDocument(android.content.ContentResolver, android.net.Uri);
     method public static java.util.List<java.lang.String> findDocumentPath(android.content.ContentResolver, android.net.Uri);
     method public static java.lang.String getDocumentId(android.net.Uri);
@@ -32778,6 +32850,7 @@
     field public static final int FLAG_SUPPORTS_THUMBNAIL = 1; // 0x1
     field public static final int FLAG_SUPPORTS_WRITE = 2; // 0x2
     field public static final int FLAG_VIRTUAL_DOCUMENT = 512; // 0x200
+    field public static final int FLAG_WEB_LINKABLE = 4096; // 0x1000
     field public static final java.lang.String MIME_TYPE_DIR = "vnd.android.document/directory";
   }
 
@@ -32811,6 +32884,7 @@
     ctor public DocumentsProvider();
     method public java.lang.String copyDocument(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
     method public java.lang.String createDocument(java.lang.String, java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
+    method public android.content.IntentSender createWebLinkIntent(java.lang.String, android.os.Bundle) throws java.io.FileNotFoundException;
     method public final int delete(android.net.Uri, java.lang.String, java.lang.String[]);
     method public void deleteDocument(java.lang.String) throws java.io.FileNotFoundException;
     method public android.provider.DocumentsContract.Path findDocumentPath(java.lang.String, java.lang.String) throws java.io.FileNotFoundException;
@@ -35327,6 +35401,7 @@
     field public static final java.lang.String EXTRA_DATASET_EXTRAS = "android.service.autofill.extra.DATASET_EXTRAS";
     field public static final java.lang.String EXTRA_RESPONSE_EXTRAS = "android.service.autofill.extra.RESPONSE_EXTRAS";
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
+    field public static final java.lang.String SERVICE_META_DATA = "android.autofill";
   }
 
   public final class FillCallback {
@@ -35532,7 +35607,6 @@
     field public static final java.lang.String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
     field public static final java.lang.String EXTRA_RECENT = "android.service.media.extra.RECENT";
     field public static final java.lang.String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
-    field public static final java.lang.String EXTRA_SUGGESTION_KEYWORDS = "android.service.media.extra.SUGGESTION_KEYWORDS";
   }
 
   public class MediaBrowserService.Result<T> {
@@ -41980,8 +42054,8 @@
     method public static int convertObjectIdToOrdinal(int);
     method public void dump(java.lang.String);
     method public void end(long);
-    method public void endObject(long);
-    method public void endRepeatedObject(long);
+    method public deprecated void endObject(long);
+    method public deprecated void endRepeatedObject(long);
     method public void flush();
     method public byte[] getBytes();
     method public static int getDepthFromToken(long);
@@ -41992,8 +42066,8 @@
     method public static long makeFieldId(int, long);
     method public static long makeToken(int, boolean, int, int, int);
     method public long start(long);
-    method public long startObject(long);
-    method public long startRepeatedObject(long);
+    method public deprecated long startObject(long);
+    method public deprecated long startRepeatedObject(long);
     method public static java.lang.String token2String(long);
     method public void write(long, double);
     method public void write(long, float);
@@ -42002,57 +42076,55 @@
     method public void write(long, boolean);
     method public void write(long, java.lang.String);
     method public void write(long, byte[]);
-    method public void writeBool(long, boolean);
-    method public void writeBytes(long, byte[]);
-    method public void writeDouble(long, double);
-    method public void writeEnum(long, int);
-    method public void writeFixed32(long, int);
-    method public void writeFixed64(long, long);
-    method public void writeFloat(long, float);
-    method public void writeInt32(long, int);
-    method public void writeInt64(long, long);
-    method public void writeObject(long, byte[]);
-    method public void writeObjectImpl(int, byte[]);
-    method public void writePackedBool(long, boolean[]);
-    method public void writePackedDouble(long, double[]);
-    method public void writePackedEnum(long, int[]);
-    method public void writePackedFixed32(long, int[]);
-    method public void writePackedFixed64(long, long[]);
-    method public void writePackedFloat(long, float[]);
-    method public void writePackedInt32(long, int[]);
-    method public void writePackedInt64(long, long[]);
-    method public void writePackedSFixed32(long, int[]);
-    method public void writePackedSFixed64(long, long[]);
-    method public void writePackedSInt32(long, int[]);
-    method public void writePackedSInt64(long, long[]);
-    method public void writePackedUInt32(long, int[]);
-    method public void writePackedUInt64(long, long[]);
-    method public void writeRepeatedBool(long, boolean);
-    method public void writeRepeatedBytes(long, byte[]);
-    method public void writeRepeatedDouble(long, double);
-    method public void writeRepeatedEnum(long, int);
-    method public void writeRepeatedFixed32(long, int);
-    method public void writeRepeatedFixed64(long, long);
-    method public void writeRepeatedFloat(long, float);
-    method public void writeRepeatedInt32(long, int);
-    method public void writeRepeatedInt64(long, long);
-    method public void writeRepeatedObject(long, byte[]);
-    method public void writeRepeatedObjectImpl(int, byte[]);
-    method public void writeRepeatedSFixed32(long, int);
-    method public void writeRepeatedSFixed64(long, long);
-    method public void writeRepeatedSInt32(long, int);
-    method public void writeRepeatedSInt64(long, long);
-    method public void writeRepeatedString(long, java.lang.String);
-    method public void writeRepeatedUInt32(long, int);
-    method public void writeRepeatedUInt64(long, long);
-    method public void writeSFixed32(long, int);
-    method public void writeSFixed64(long, long);
-    method public void writeSInt32(long, int);
-    method public void writeSInt64(long, long);
-    method public void writeString(long, java.lang.String);
+    method public deprecated void writeBool(long, boolean);
+    method public deprecated void writeBytes(long, byte[]);
+    method public deprecated void writeDouble(long, double);
+    method public deprecated void writeEnum(long, int);
+    method public deprecated void writeFixed32(long, int);
+    method public deprecated void writeFixed64(long, long);
+    method public deprecated void writeFloat(long, float);
+    method public deprecated void writeInt32(long, int);
+    method public deprecated void writeInt64(long, long);
+    method public deprecated void writeObject(long, byte[]);
+    method public deprecated void writePackedBool(long, boolean[]);
+    method public deprecated void writePackedDouble(long, double[]);
+    method public deprecated void writePackedEnum(long, int[]);
+    method public deprecated void writePackedFixed32(long, int[]);
+    method public deprecated void writePackedFixed64(long, long[]);
+    method public deprecated void writePackedFloat(long, float[]);
+    method public deprecated void writePackedInt32(long, int[]);
+    method public deprecated void writePackedInt64(long, long[]);
+    method public deprecated void writePackedSFixed32(long, int[]);
+    method public deprecated void writePackedSFixed64(long, long[]);
+    method public deprecated void writePackedSInt32(long, int[]);
+    method public deprecated void writePackedSInt64(long, long[]);
+    method public deprecated void writePackedUInt32(long, int[]);
+    method public deprecated void writePackedUInt64(long, long[]);
+    method public deprecated void writeRepeatedBool(long, boolean);
+    method public deprecated void writeRepeatedBytes(long, byte[]);
+    method public deprecated void writeRepeatedDouble(long, double);
+    method public deprecated void writeRepeatedEnum(long, int);
+    method public deprecated void writeRepeatedFixed32(long, int);
+    method public deprecated void writeRepeatedFixed64(long, long);
+    method public deprecated void writeRepeatedFloat(long, float);
+    method public deprecated void writeRepeatedInt32(long, int);
+    method public deprecated void writeRepeatedInt64(long, long);
+    method public deprecated void writeRepeatedObject(long, byte[]);
+    method public deprecated void writeRepeatedSFixed32(long, int);
+    method public deprecated void writeRepeatedSFixed64(long, long);
+    method public deprecated void writeRepeatedSInt32(long, int);
+    method public deprecated void writeRepeatedSInt64(long, long);
+    method public deprecated void writeRepeatedString(long, java.lang.String);
+    method public deprecated void writeRepeatedUInt32(long, int);
+    method public deprecated void writeRepeatedUInt64(long, long);
+    method public deprecated void writeSFixed32(long, int);
+    method public deprecated void writeSFixed64(long, long);
+    method public deprecated void writeSInt32(long, int);
+    method public deprecated void writeSInt64(long, long);
+    method public deprecated void writeString(long, java.lang.String);
     method public void writeTag(int, int);
-    method public void writeUInt32(long, int);
-    method public void writeUInt64(long, long);
+    method public deprecated void writeUInt32(long, int);
+    method public deprecated void writeUInt64(long, long);
     field public static final long FIELD_COUNT_MASK = 16492674416640L; // 0xf0000000000L
     field public static final long FIELD_COUNT_PACKED = 5497558138880L; // 0x50000000000L
     field public static final long FIELD_COUNT_REPEATED = 2199023255552L; // 0x20000000000L
@@ -45406,6 +45478,7 @@
     method public int getDrawingOrder();
     method public java.lang.CharSequence getError();
     method public android.os.Bundle getExtras();
+    method public java.lang.CharSequence getHintText();
     method public int getInputType();
     method public android.view.accessibility.AccessibilityNodeInfo getLabelFor();
     method public android.view.accessibility.AccessibilityNodeInfo getLabeledBy();
@@ -45440,6 +45513,7 @@
     method public boolean isPassword();
     method public boolean isScrollable();
     method public boolean isSelected();
+    method public boolean isShowingHintText();
     method public boolean isVisibleToUser();
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View);
     method public static android.view.accessibility.AccessibilityNodeInfo obtain(android.view.View, int);
@@ -45473,6 +45547,7 @@
     method public void setError(java.lang.CharSequence);
     method public void setFocusable(boolean);
     method public void setFocused(boolean);
+    method public void setHintText(java.lang.CharSequence);
     method public void setImportantForAccessibility(boolean);
     method public void setInputType(int);
     method public void setLabelFor(android.view.View);
@@ -45492,6 +45567,7 @@
     method public void setRangeInfo(android.view.accessibility.AccessibilityNodeInfo.RangeInfo);
     method public void setScrollable(boolean);
     method public void setSelected(boolean);
+    method public void setShowingHintText(boolean);
     method public void setSource(android.view.View);
     method public void setSource(android.view.View, int);
     method public void setText(java.lang.CharSequence);
@@ -53431,6 +53507,133 @@
 
 }
 
+package java.lang.invoke {
+
+  public class LambdaConversionException extends java.lang.Exception {
+    ctor public LambdaConversionException();
+    ctor public LambdaConversionException(java.lang.String);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.Throwable);
+    ctor public LambdaConversionException(java.lang.String, java.lang.Throwable, boolean, boolean);
+  }
+
+  public abstract class MethodHandle {
+    method public java.lang.invoke.MethodHandle asFixedArity();
+    method public java.lang.invoke.MethodHandle asType(java.lang.invoke.MethodType);
+    method public java.lang.invoke.MethodHandle asVarargsCollector(java.lang.Class<?>);
+    method public java.lang.invoke.MethodHandle bindTo(java.lang.Object);
+    method public final java.lang.Object invoke(java.lang.Object...) throws java.lang.Throwable;
+    method public final java.lang.Object invokeExact(java.lang.Object...) throws java.lang.Throwable;
+    method public java.lang.Object invokeWithArguments(java.util.List<?>) throws java.lang.Throwable;
+    method public boolean isVarargsCollector();
+    method public java.lang.invoke.MethodType type();
+  }
+
+  public abstract interface MethodHandleInfo {
+    method public abstract java.lang.Class<?> getDeclaringClass();
+    method public abstract java.lang.invoke.MethodType getMethodType();
+    method public abstract int getModifiers();
+    method public abstract java.lang.String getName();
+    method public abstract int getReferenceKind();
+    method public default boolean isVarArgs();
+    method public static boolean refKindIsField(int);
+    method public static boolean refKindIsValid(int);
+    method public static java.lang.String refKindName(int);
+    method public static java.lang.String referenceKindToString(int);
+    method public abstract <T extends java.lang.reflect.Member> T reflectAs(java.lang.Class<T>, java.lang.invoke.MethodHandles.Lookup);
+    method public static java.lang.String toString(int, java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType);
+    field public static final int REF_getField = 1; // 0x1
+    field public static final int REF_getStatic = 2; // 0x2
+    field public static final int REF_invokeInterface = 9; // 0x9
+    field public static final int REF_invokeSpecial = 7; // 0x7
+    field public static final int REF_invokeStatic = 6; // 0x6
+    field public static final int REF_invokeVirtual = 5; // 0x5
+    field public static final int REF_newInvokeSpecial = 8; // 0x8
+    field public static final int REF_putField = 3; // 0x3
+    field public static final int REF_putStatic = 4; // 0x4
+  }
+
+  public class MethodHandles {
+    method public static java.lang.invoke.MethodHandle arrayElementGetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
+    method public static java.lang.invoke.MethodHandle arrayElementSetter(java.lang.Class<?>) throws java.lang.IllegalArgumentException;
+    method public static java.lang.invoke.MethodHandle catchException(java.lang.invoke.MethodHandle, java.lang.Class<? extends java.lang.Throwable>, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle constant(java.lang.Class<?>, java.lang.Object);
+    method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodHandle dropArguments(java.lang.invoke.MethodHandle, int, java.lang.Class<?>...);
+    method public static java.lang.invoke.MethodHandle exactInvoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandle filterReturnValue(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle guardWithTest(java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle, java.lang.invoke.MethodHandle);
+    method public static java.lang.invoke.MethodHandle identity(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodHandle invoker(java.lang.invoke.MethodType);
+    method public static java.lang.invoke.MethodHandles.Lookup lookup();
+    method public static java.lang.invoke.MethodHandle permuteArguments(java.lang.invoke.MethodHandle, java.lang.invoke.MethodType, int...);
+    method public static java.lang.invoke.MethodHandles.Lookup publicLookup();
+    method public static java.lang.invoke.MethodHandle throwException(java.lang.Class<?>, java.lang.Class<? extends java.lang.Throwable>);
+  }
+
+  public static final class MethodHandles.Lookup {
+    method public java.lang.invoke.MethodHandle bind(java.lang.Object, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findConstructor(java.lang.Class<?>, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findSpecial(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStatic(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandle findStaticGetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findStaticSetter(java.lang.Class<?>, java.lang.String, java.lang.Class<?>) throws java.lang.IllegalAccessException, java.lang.NoSuchFieldException;
+    method public java.lang.invoke.MethodHandle findVirtual(java.lang.Class<?>, java.lang.String, java.lang.invoke.MethodType) throws java.lang.IllegalAccessException, java.lang.NoSuchMethodException;
+    method public java.lang.invoke.MethodHandles.Lookup in(java.lang.Class<?>);
+    method public java.lang.Class<?> lookupClass();
+    method public int lookupModes();
+    method public void throwMakeAccessException(java.lang.String, java.lang.Object) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflect(java.lang.reflect.Method) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectConstructor(java.lang.reflect.Constructor<?>) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectGetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSetter(java.lang.reflect.Field) throws java.lang.IllegalAccessException;
+    method public java.lang.invoke.MethodHandle unreflectSpecial(java.lang.reflect.Method, java.lang.Class<?>) throws java.lang.IllegalAccessException;
+    field public static final int PACKAGE = 8; // 0x8
+    field public static final int PRIVATE = 2; // 0x2
+    field public static final int PROTECTED = 4; // 0x4
+    field public static final int PUBLIC = 1; // 0x1
+  }
+
+  public final class MethodType implements java.io.Serializable {
+    method public java.lang.invoke.MethodType appendParameterTypes(java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType appendParameterTypes(java.util.List<java.lang.Class<?>>);
+    method public java.lang.invoke.MethodType changeParameterType(int, java.lang.Class<?>);
+    method public java.lang.invoke.MethodType changeReturnType(java.lang.Class<?>);
+    method public java.lang.invoke.MethodType dropParameterTypes(int, int);
+    method public java.lang.invoke.MethodType erase();
+    method public static java.lang.invoke.MethodType fromMethodDescriptorString(java.lang.String, java.lang.ClassLoader) throws java.lang.IllegalArgumentException, java.lang.TypeNotPresentException;
+    method public java.lang.invoke.MethodType generic();
+    method public static java.lang.invoke.MethodType genericMethodType(int, boolean);
+    method public static java.lang.invoke.MethodType genericMethodType(int);
+    method public boolean hasPrimitives();
+    method public boolean hasWrappers();
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.lang.Class<?>...);
+    method public java.lang.invoke.MethodType insertParameterTypes(int, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>[]);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.util.List<java.lang.Class<?>>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>, java.lang.Class<?>...);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.Class<?>);
+    method public static java.lang.invoke.MethodType methodType(java.lang.Class<?>, java.lang.invoke.MethodType);
+    method public java.lang.Class<?>[] parameterArray();
+    method public int parameterCount();
+    method public java.util.List<java.lang.Class<?>> parameterList();
+    method public java.lang.Class<?> parameterType(int);
+    method public java.lang.Class<?> returnType();
+    method public java.lang.String toMethodDescriptorString();
+    method public java.lang.invoke.MethodType unwrap();
+    method public java.lang.invoke.MethodType wrap();
+  }
+
+  public class WrongMethodTypeException extends java.lang.RuntimeException {
+    ctor public WrongMethodTypeException();
+    ctor public WrongMethodTypeException(java.lang.String);
+  }
+
+}
+
 package java.lang.ref {
 
   public class PhantomReference<T> extends java.lang.ref.Reference {
@@ -56156,8 +56359,10 @@
   public final class FileTime implements java.lang.Comparable {
     method public int compareTo(java.nio.file.attribute.FileTime);
     method public static java.nio.file.attribute.FileTime from(long, java.util.concurrent.TimeUnit);
+    method public static java.nio.file.attribute.FileTime from(java.time.Instant);
     method public static java.nio.file.attribute.FileTime fromMillis(long);
     method public long to(java.util.concurrent.TimeUnit);
+    method public java.time.Instant toInstant();
     method public long toMillis();
   }
 
@@ -61814,6 +62019,7 @@
     method public boolean before(java.util.Date);
     method public java.lang.Object clone();
     method public int compareTo(java.util.Date);
+    method public static java.util.Date from(java.time.Instant);
     method public deprecated int getDate();
     method public deprecated int getDay();
     method public deprecated int getHours();
@@ -61832,6 +62038,7 @@
     method public void setTime(long);
     method public deprecated void setYear(int);
     method public deprecated java.lang.String toGMTString();
+    method public java.time.Instant toInstant();
     method public deprecated java.lang.String toLocaleString();
   }
 
diff --git a/cmds/app_process/app_main.cpp b/cmds/app_process/app_main.cpp
index d5580ac..0ea141c 100644
--- a/cmds/app_process/app_main.cpp
+++ b/cmds/app_process/app_main.cpp
@@ -184,10 +184,6 @@
 
 int main(int argc, char* const argv[])
 {
-    if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) < 0) {
-        LOG_ALWAYS_FATAL("PR_SET_NO_NEW_PRIVS failed: %s", strerror(errno));
-    }
-
     if (!LOG_NDEBUG) {
       String8 argv_String;
       for (int i = 0; i < argc; ++i) {
diff --git a/cmds/svc/src/com/android/commands/svc/NfcCommand.java b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
index 8e9791f..02a92b9 100644
--- a/cmds/svc/src/com/android/commands/svc/NfcCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/NfcCommand.java
@@ -58,7 +58,8 @@
                 IPackageManager pm = IPackageManager.Stub.asInterface(
                         ServiceManager.getService("package"));
                 try {
-                    if (pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0)) {
+                    if (pm.hasSystemFeature(PackageManager.FEATURE_NFC, 0) ||
+			pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION, 0)) {
                         INfcAdapter nfc = INfcAdapter.Stub
                                 .asInterface(ServiceManager.getService(Context.NFC_SERVICE));
                         try {
diff --git a/cmds/uiautomator/library/Android.mk b/cmds/uiautomator/library/Android.mk
index af2e25a..de46b8c 100644
--- a/cmds/uiautomator/library/Android.mk
+++ b/cmds/uiautomator/library/Android.mk
@@ -29,6 +29,7 @@
 LOCAL_SRC_FILES := $(uiautomator.core_src_files)
 LOCAL_MODULE := uiautomator.core
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
 ###############################################
@@ -36,6 +37,7 @@
 include $(CLEAR_VARS)
 LOCAL_SRC_FILES := $(uiautomator.core_src_files)
 LOCAL_JAVA_LIBRARIES := $(uiautomator.core_java_libraries)
+LOCAL_STATIC_JAVA_LIBRARIES := legacy-android-test
 LOCAL_MODULE_CLASS := JAVA_LIBRARIES
 LOCAL_DROIDDOC_SOURCE_PATH := $(LOCAL_PATH)/core-src \
 	$(LOCAL_PATH)/testrunner-src
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 07a8253..b76aeb7 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -414,9 +414,9 @@
     public int flags;
 
     /**
-     * The unique string Id to identify the accessibility service.
+     * The component name the accessibility service.
      */
-    private String mId;
+    private ComponentName mComponentName;
 
     /**
      * The Service that implements this accessibility service component.
@@ -464,7 +464,7 @@
     public AccessibilityServiceInfo(ResolveInfo resolveInfo, Context context)
             throws XmlPullParserException, IOException {
         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
-        mId = new ComponentName(serviceInfo.packageName, serviceInfo.name).flattenToShortString();
+        mComponentName = new ComponentName(serviceInfo.packageName, serviceInfo.name);
         mResolveInfo = resolveInfo;
 
         XmlResourceParser parser = null;
@@ -574,7 +574,14 @@
      * @hide
      */
     public void setComponentName(ComponentName component) {
-        mId = component.flattenToShortString();
+        mComponentName = component;
+    }
+
+    /**
+     * @hide
+     */
+    public ComponentName getComponentName() {
+        return mComponentName;
     }
 
     /**
@@ -585,7 +592,7 @@
      * @return The id.
      */
     public String getId() {
-        return mId;
+        return mComponentName.flattenToShortString();
     }
 
     /**
@@ -715,7 +722,7 @@
         parcel.writeInt(feedbackType);
         parcel.writeLong(notificationTimeout);
         parcel.writeInt(flags);
-        parcel.writeString(mId);
+        parcel.writeParcelable(mComponentName, flagz);
         parcel.writeParcelable(mResolveInfo, 0);
         parcel.writeString(mSettingsActivityName);
         parcel.writeInt(mCapabilities);
@@ -729,7 +736,7 @@
         feedbackType = parcel.readInt();
         notificationTimeout = parcel.readLong();
         flags = parcel.readInt();
-        mId = parcel.readString();
+        mComponentName = parcel.readParcelable(this.getClass().getClassLoader());
         mResolveInfo = parcel.readParcelable(null);
         mSettingsActivityName = parcel.readString();
         mCapabilities = parcel.readInt();
@@ -739,7 +746,7 @@
 
     @Override
     public int hashCode() {
-        return 31 * 1 + ((mId == null) ? 0 : mId.hashCode());
+        return 31 * 1 + ((mComponentName == null) ? 0 : mComponentName.hashCode());
     }
 
     @Override
@@ -754,11 +761,11 @@
             return false;
         }
         AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
-        if (mId == null) {
-            if (other.mId != null) {
+        if (mComponentName == null) {
+            if (other.mComponentName != null) {
                 return false;
             }
-        } else if (!mId.equals(other.mId)) {
+        } else if (!mComponentName.equals(other.mComponentName)) {
             return false;
         }
         return true;
@@ -777,7 +784,7 @@
         stringBuilder.append(", ");
         appendFlags(stringBuilder, flags);
         stringBuilder.append(", ");
-        stringBuilder.append("id: ").append(mId);
+        stringBuilder.append("id: ").append(getId());
         stringBuilder.append(", ");
         stringBuilder.append("resolveInfo: ").append(mResolveInfo);
         stringBuilder.append(", ");
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 3170d0d..2e3c100 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -628,6 +628,10 @@
             return stackId >= FIRST_STATIC_STACK_ID && stackId <= LAST_STATIC_STACK_ID;
         }
 
+        public static boolean isDynamicStack(int stackId) {
+            return stackId >= FIRST_DYNAMIC_STACK_ID;
+        }
+
         /**
          * Returns true if the activities contained in the input stack display a shadow around
          * their border.
@@ -825,7 +829,7 @@
         /** Returns true if the input stack and its content can affect the device orientation. */
         public static boolean canSpecifyOrientation(int stackId) {
             return stackId == HOME_STACK_ID || stackId == RECENTS_STACK_ID
-                    || stackId == FULLSCREEN_WORKSPACE_STACK_ID;
+                    || stackId == FULLSCREEN_WORKSPACE_STACK_ID || isDynamicStack(stackId);
         }
     }
 
@@ -2172,6 +2176,12 @@
             dest.writeParcelable(mContentInsets, 0);
         }
 
+        @Override
+        public String toString() {
+            return "TaskSnapshot{mSnapshot=" + mSnapshot + " mOrientation=" + mOrientation
+                    + " mContentInsets=" + mContentInsets.toShortString();
+        }
+
         public static final Creator<TaskSnapshot> CREATOR = new Creator<TaskSnapshot>() {
             public TaskSnapshot createFromParcel(Parcel source) {
                 return new TaskSnapshot(source);
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 105d2ca..20a9a93 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -807,7 +807,7 @@
                 default:
                     throw new IllegalArgumentException("Unknown cmd: " + op.cmd);
             }
-            if (!mAllowOptimization && op.cmd != OP_ADD) {
+            if (!mAllowOptimization && op.cmd != OP_REMOVE) {
                 mManager.moveFragmentToExpectedState(f);
             }
         }
@@ -873,6 +873,29 @@
         }
     }
 
+    /**
+     * Removes fragments that are added or removed during a pop operation.
+     *
+     * @param added Initialized to the fragments that are in the mManager.mAdded, this
+     *              will be modified to contain the fragments that will be in mAdded
+     *              after the execution ({@link #executeOps()}.
+     */
+    void trackAddedFragmentsInPop(ArrayList<Fragment> added) {
+        for (int opNum = 0; opNum < mOps.size(); opNum++) {
+            final Op op = mOps.get(opNum);
+            switch (op.cmd) {
+                case OP_ADD:
+                case OP_ATTACH:
+                    added.remove(op.fragment);
+                    break;
+                case OP_REMOVE:
+                case OP_DETACH:
+                    added.add(op.fragment);
+                    break;
+            }
+        }
+    }
+
     boolean isPostponed() {
         for (int opNum = 0; opNum < mOps.size(); opNum++) {
             final Op op = mOps.get(opNum);
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 10ab2bc..62d6898 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -102,15 +102,19 @@
         mSavedFragmentState = in.readBundle();
     }
 
-    public Fragment instantiate(FragmentHostCallback host, Fragment parent,
-            FragmentManagerNonConfig childNonConfig) {
+    public Fragment instantiate(FragmentHostCallback host, FragmentContainer container,
+            Fragment parent, FragmentManagerNonConfig childNonConfig) {
         if (mInstance == null) {
             final Context context = host.getContext();
             if (mArguments != null) {
                 mArguments.setClassLoader(context.getClassLoader());
             }
 
-            mInstance = Fragment.instantiate(context, mClassName, mArguments);
+            if (container != null) {
+                mInstance = container.instantiate(context, mClassName, mArguments);
+            } else {
+                mInstance = Fragment.instantiate(context, mClassName, mArguments);
+            }
 
             if (mSavedFragmentState != null) {
                 mSavedFragmentState.setClassLoader(context.getClassLoader());
diff --git a/core/java/android/app/FragmentContainer.java b/core/java/android/app/FragmentContainer.java
index b2e0300..6ed54dc 100644
--- a/core/java/android/app/FragmentContainer.java
+++ b/core/java/android/app/FragmentContainer.java
@@ -18,6 +18,8 @@
 
 import android.annotation.IdRes;
 import android.annotation.Nullable;
+import android.content.Context;
+import android.os.Bundle;
 import android.view.View;
 
 /**
@@ -35,4 +37,13 @@
      * Return {@code true} if the container holds any view.
      */
     public abstract boolean onHasView();
+
+    /**
+     * Creates an instance of the specified fragment, can be overridden to construct fragments
+     * with dependencies, or change the fragment being constructed. By default just calls
+     * {@link Fragment#instantiate(Context, String, Bundle)}.
+     */
+    public Fragment instantiate(Context context, String className, Bundle arguments) {
+        return Fragment.instantiate(context, className, arguments);
+    }
 }
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 92ba440..44f1322 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -31,6 +31,7 @@
 import android.os.Looper;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArraySet;
 import android.util.AttributeSet;
 import android.util.DebugUtils;
 import android.util.Log;
@@ -1245,11 +1246,13 @@
                         dispatchOnFragmentViewDestroyed(f, false);
                         if (f.mView != null && f.mContainer != null) {
                             Animator anim = null;
-                            if (mCurState > Fragment.INITIALIZING && !mDestroyed &&
-                                    f.mView.getVisibility() == View.VISIBLE) {
+                            if (mCurState > Fragment.INITIALIZING && !mDestroyed
+                                    && f.mView.getVisibility() == View.VISIBLE
+                                    && f.mView.getTransitionAlpha() > 0) {
                                 anim = loadAnimator(f, transit, false,
                                         transitionStyle);
                             }
+                            f.mView.setTransitionAlpha(1f);
                             if (anim != null) {
                                 final ViewGroup container = f.mContainer;
                                 final View view = f.mView;
@@ -1439,7 +1442,7 @@
             }
             if (f.mIsNewlyAdded && f.mContainer != null) {
                 // Make it visible and run the animations
-                f.mView.setVisibility(View.VISIBLE);
+                f.mView.setTransitionAlpha(1f);
                 f.mIsNewlyAdded = false;
                 // run animations:
                 Animator anim = loadAnimator(f, f.getNextTransition(), true, f.getNextTransitionStyle());
@@ -1981,11 +1984,13 @@
                 if (startIndex != recordNum) {
                     executeOpsTogether(records, isRecordPop, startIndex, recordNum);
                 }
-                // execute all unoptimized together
-                int optimizeEnd;
-                for (optimizeEnd = recordNum + 1; optimizeEnd < numRecords; optimizeEnd++) {
-                    if (records.get(optimizeEnd).mAllowOptimization) {
-                        break;
+                // execute all unoptimized pop operations together or one add operation
+                int optimizeEnd = recordNum + 1;
+                if (isRecordPop.get(recordNum)) {
+                    while (optimizeEnd < numRecords
+                            && isRecordPop.get(optimizeEnd)
+                            && !records.get(optimizeEnd).mAllowOptimization) {
+                        optimizeEnd++;
                     }
                 }
                 executeOpsTogether(records, isRecordPop, recordNum, optimizeEnd);
@@ -2023,6 +2028,8 @@
             final boolean isPop = isRecordPop.get(recordNum);
             if (!isPop) {
                 record.expandReplaceOps(mTmpAddedFragments);
+            } else {
+                record.trackAddedFragmentsInPop(mTmpAddedFragments);
             }
             final int bumpAmount = isPop ? -1 : 1;
             record.bumpBackStackNesting(bumpAmount);
@@ -2038,9 +2045,11 @@
 
         int postponeIndex = endIndex;
         if (allowOptimization) {
-            moveFragmentsToInvisible();
+            ArraySet<Fragment> addedFragments = new ArraySet<>();
+            addAddedFragments(addedFragments);
             postponeIndex = postponePostponableTransactions(records, isRecordPop,
-                    startIndex, endIndex);
+                    startIndex, endIndex, addedFragments);
+            makeRemovedFragmentsInvisible(addedFragments);
         }
 
         if (postponeIndex != startIndex && allowOptimization) {
@@ -2065,6 +2074,24 @@
     }
 
     /**
+     * Any fragments that were removed because they have been postponed should have their views
+     * made invisible by setting their transition alpha to 0.
+     *
+     * @param fragments The fragments that were added during operation execution. Only the ones
+     *                  that are no longer added will have their transition alpha changed.
+     */
+    private void makeRemovedFragmentsInvisible(ArraySet<Fragment> fragments) {
+        final int numAdded = fragments.size();
+        for (int i = 0; i < numAdded; i++) {
+            final Fragment fragment = fragments.valueAt(i);
+            if (!fragment.mAdded) {
+                final View view = fragment.getView();
+                view.setTransitionAlpha(0f);
+            }
+        }
+    }
+
+    /**
      * Examine all transactions and determine which ones are marked as postponed. Those will
      * have their operations rolled back and moved to the end of the record list (up to endIndex).
      * It will also add the postponed transaction to the queue.
@@ -2077,7 +2104,8 @@
      * postponed.
      */
     private int postponePostponableTransactions(ArrayList<BackStackRecord> records,
-            ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
+            ArrayList<Boolean> isRecordPop, int startIndex, int endIndex,
+            ArraySet<Fragment> added) {
         int postponeIndex = endIndex;
         for (int i = endIndex - 1; i >= startIndex; i--) {
             final BackStackRecord record = records.get(i);
@@ -2108,7 +2136,7 @@
                 }
 
                 // different views may be visible now
-                moveFragmentsToInvisible();
+                addAddedFragments(added);
             }
         }
         return postponeIndex;
@@ -2141,14 +2169,16 @@
         }
         if (moveToState) {
             moveToState(mCurState, true);
-        } else if (mActive != null) {
+        }
+
+        if (mActive != null) {
             final int numActive = mActive.size();
             for (int i = 0; i < numActive; i++) {
                 // Allow added fragments to be removed during the pop since we aren't going
                 // to move them to the final state with moveToState(mCurState).
                 Fragment fragment = mActive.get(i);
-                if (fragment.mView != null && fragment.mIsNewlyAdded &&
-                        record.interactsWith(fragment.mContainerId)) {
+                if (fragment != null && fragment.mView != null && fragment.mIsNewlyAdded
+                        && record.interactsWith(fragment.mContainerId)) {
                     fragment.mIsNewlyAdded = false;
                 }
             }
@@ -2213,10 +2243,11 @@
 
     /**
      * Ensure that fragments that are added are moved to at least the CREATED state.
-     * Any newly-added Views are made INVISIBLE so that the Transaction can be postponed
-     * with {@link Fragment#postponeEnterTransition()}.
+     * Any newly-added Views are inserted into {@code added} so that the Transaction can be
+     * postponed with {@link Fragment#postponeEnterTransition()}. They will later be made
+     * invisible by changing their transitionAlpha to 0 if they have been removed when postponed.
      */
-    private void moveFragmentsToInvisible() {
+    private void addAddedFragments(ArraySet<Fragment> added) {
         if (mCurState < Fragment.CREATED) {
             return;
         }
@@ -2228,7 +2259,7 @@
             if (fragment.mState < state) {
                 moveToState(fragment, state, fragment.getNextAnim(), fragment.getNextTransition(), false);
                 if (fragment.mView != null && !fragment.mHidden && fragment.mIsNewlyAdded) {
-                    fragment.mView.setVisibility(View.INVISIBLE);
+                    added.add(fragment);
                 }
             }
         }
@@ -2622,7 +2653,7 @@
                 if (childNonConfigs != null && i < childNonConfigs.size()) {
                     childNonConfig = childNonConfigs.get(i);
                 }
-                Fragment f = fs.instantiate(mHost, mParent, childNonConfig);
+                Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig);
                 if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
                 mActive.add(f);
                 // Now that the fragment is instantiated (or came from being
@@ -3241,7 +3272,7 @@
                 + Integer.toHexString(id) + " fname=" + fname
                 + " existing=" + fragment);
         if (fragment == null) {
-            fragment = Fragment.instantiate(context, fname);
+            fragment = mContainer.instantiate(context, fname, null);
             fragment.mFromLayout = true;
             fragment.mFragmentId = id != 0 ? id : containerId;
             fragment.mContainerId = containerId;
diff --git a/core/java/android/app/FragmentTransition.java b/core/java/android/app/FragmentTransition.java
index 3324448..80a5aac 100644
--- a/core/java/android/app/FragmentTransition.java
+++ b/core/java/android/app/FragmentTransition.java
@@ -188,7 +188,10 @@
     private static void configureTransitionsOptimized(FragmentManagerImpl fragmentManager,
             int containerId, FragmentContainerTransition fragments,
             View nonExistentView, ArrayMap<String, String> nameOverrides) {
-        ViewGroup sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+        ViewGroup sceneRoot = null;
+        if (fragmentManager.mContainer.onHasView()) {
+            sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+        }
         if (sceneRoot == null) {
             return;
         }
@@ -257,7 +260,10 @@
     private static void configureTransitionsUnoptimized(FragmentManagerImpl fragmentManager,
             int containerId, FragmentContainerTransition fragments,
             View nonExistentView, ArrayMap<String, String> nameOverrides) {
-        ViewGroup sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+        ViewGroup sceneRoot = null;
+        if (fragmentManager.mContainer.onHasView()) {
+            sceneRoot = (ViewGroup) fragmentManager.mContainer.onFindViewById(containerId);
+        }
         if (sceneRoot == null) {
             return;
         }
@@ -1266,8 +1272,9 @@
             case BackStackRecord.OP_REMOVE:
             case BackStackRecord.OP_DETACH:
                 if (isOptimizedTransaction) {
-                    setFirstOut = !fragment.mAdded && fragment.mView != null &&
-                            fragment.mView.getVisibility() == View.VISIBLE;
+                    setFirstOut = !fragment.mAdded && fragment.mView != null
+                            && fragment.mView.getVisibility() == View.VISIBLE
+                            && fragment.mView.getTransitionAlpha() > 0;
                 } else {
                     setFirstOut = fragment.mAdded && !fragment.mHidden;
                 }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 21ae853..5824c32 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -31,7 +31,6 @@
 import android.app.ITaskStackListener;
 import android.app.IUiAutomationConnection;
 import android.app.IUidObserver;
-
 import android.app.IUserSwitchObserver;
 import android.app.Notification;
 import android.app.PendingIntent;
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index ef997c9..6deedb6 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -102,4 +102,9 @@
      * been locked.
      */
     void onTaskProfileLocked(int taskId, int userId);
+
+    /**
+     * Called when a task snapshot got updated.
+     */
+    void onTaskSnapshotChanged(int taskId, in ActivityManager.TaskSnapshot snapshot);
 }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 119b055..5b74e23 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -70,6 +70,7 @@
 import com.android.internal.R;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.NotificationColorUtil;
+import com.android.internal.util.Preconditions;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -987,6 +988,32 @@
      */
     public static final String EXTRA_CONTAINS_CUSTOM_VIEW = "android.contains.customView";
 
+    /**
+     * {@link #extras} key: the audio contents of this notification.
+     *
+     * This is for use when rendering the notification on an audio-focused interface;
+     * the audio contents are a complete sound sample that contains the contents/body of the
+     * notification. This may be used in substitute of a Text-to-Speech reading of the
+     * notification. For example if the notification represents a voice message this should point
+     * to the audio of that message.
+     *
+     * The data stored under this key should be a String representation of a Uri that contains the
+     * audio contents in one of the following formats: WAV, PCM 16-bit, AMR-WB.
+     *
+     * This extra is unnecessary if you are using {@code MessagingStyle} since each {@code Message}
+     * has a field for holding data URI. That field can be used for audio.
+     * See {@code Message#setData}.
+     *
+     * Example usage:
+     * <pre>
+     * {@code
+     * Notification.Builder myBuilder = (build your Notification as normal);
+     * myBuilder.getExtras().putString(EXTRA_AUDIO_CONTENTS_URI, myAudioUri.toString());
+     * }
+     * </pre>
+     */
+    public static final String EXTRA_AUDIO_CONTENTS_URI = "android.audioContents";
+
     /** @hide */
     @SystemApi
     public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
@@ -1006,6 +1033,21 @@
      * to attach actions.
      */
     public static class Action implements Parcelable {
+        /**
+         * {@link #extras} key: Keys to a {@link Parcelable} {@link ArrayList} of
+         * {@link RemoteInput}s.
+         *
+         * This is intended for {@link RemoteInput}s that only accept data, meaning
+         * {@link RemoteInput#getAllowFreeFormInput} is false, {@link RemoteInput#getChoices}
+         * is null or empty, and {@link RemoteInput#getAllowedDataTypes is non-null and not
+         * empty. These {@link RemoteInput}s will be ignored by devices that do not
+         * support non-text-based {@link RemoteInput}s. See {@link Builder#build}.
+         *
+         * You can test if a RemoteInput matches these constraints using
+         * {@link RemoteInput#isDataOnly}.
+         */
+        private static final String EXTRA_DATA_ONLY_INPUTS = "android.extra.DATA_ONLY_INPUTS";
+
         private final Bundle mExtras;
         private Icon mIcon;
         private final RemoteInput[] mRemoteInputs;
@@ -1096,13 +1138,28 @@
 
         /**
          * Get the list of inputs to be collected from the user when this action is sent.
-         * May return null if no remote inputs were added.
+         * May return null if no remote inputs were added. Only returns inputs which accept
+         * a text input. For inputs which only accept data use {@link #getDataOnlyRemoteInputs}.
          */
         public RemoteInput[] getRemoteInputs() {
             return mRemoteInputs;
         }
 
         /**
+         * Get the list of inputs to be collected from the user that ONLY accept data when this
+         * action is sent. These remote inputs are guaranteed to return true on a call to
+         * {@link RemoteInput#isDataOnly}.
+         *
+         * May return null if no data-only remote inputs were added.
+         *
+         * This method exists so that legacy RemoteInput collectors that pre-date the addition
+         * of non-textual RemoteInputs do not access these remote inputs.
+         */
+        public RemoteInput[] getDataOnlyRemoteInputs() {
+            return (RemoteInput[]) mExtras.getParcelableArray(EXTRA_DATA_ONLY_INPUTS);
+        }
+
+        /**
          * Builder class for {@link Action} objects.
          */
         public static final class Builder {
@@ -1225,9 +1282,32 @@
              * @return the built action
              */
             public Action build() {
-                RemoteInput[] remoteInputs = mRemoteInputs != null
-                        ? mRemoteInputs.toArray(new RemoteInput[mRemoteInputs.size()]) : null;
-                return new Action(mIcon, mTitle, mIntent, mExtras, remoteInputs,
+                ArrayList<RemoteInput> dataOnlyInputs = new ArrayList<>();
+                RemoteInput[] previousDataInputs =
+                    (RemoteInput[]) mExtras.getParcelableArray(EXTRA_DATA_ONLY_INPUTS);
+                if (previousDataInputs != null) {
+                    for (RemoteInput input : previousDataInputs) {
+                        dataOnlyInputs.add(input);
+                    }
+                }
+                List<RemoteInput> textInputs = new ArrayList<>();
+                if (mRemoteInputs != null) {
+                    for (RemoteInput input : mRemoteInputs) {
+                        if (input.isDataOnly()) {
+                            dataOnlyInputs.add(input);
+                        } else {
+                            textInputs.add(input);
+                        }
+                    }
+                }
+                if (!dataOnlyInputs.isEmpty()) {
+                    RemoteInput[] dataInputsArr =
+                            dataOnlyInputs.toArray(new RemoteInput[dataOnlyInputs.size()]);
+                    mExtras.putParcelableArray(EXTRA_DATA_ONLY_INPUTS, dataInputsArr);
+                }
+                RemoteInput[] textInputsArr = textInputs.isEmpty()
+                        ? null : textInputs.toArray(new RemoteInput[textInputs.size()]);
+                return new Action(mIcon, mTitle, mIntent, mExtras, textInputsArr,
                         mAllowGeneratedReplies);
             }
         }
@@ -1520,7 +1600,7 @@
             /**
              * Get a hint that this Action should be displayed inline.
              *
-             * @return {@code true} if the Action should be displayed inline, {@code false} 
+             * @return {@code true} if the Action should be displayed inline, {@code false}
              *         otherwise. The default value is {@code false} if this was never set.
              */
             public boolean getHintDisplayActionInline() {
@@ -2341,6 +2421,17 @@
          */
         private int mCachedContrastColor = COLOR_INVALID;
         private int mCachedContrastColorIsFor = COLOR_INVALID;
+        /**
+         * Caches a ambient version of {@link #mCachedContrastColorIsFor}.
+         */
+        private int mCachedAmbientColor = COLOR_INVALID;
+        private int mCachedAmbientColorIsFor = COLOR_INVALID;
+
+        /**
+         * Caches an instance of StandardTemplateParams. Note that this may have been used before,
+         * so make sure to call {@link StandardTemplateParams#reset()} before using it.
+         */
+        StandardTemplateParams mParams = new StandardTemplateParams();
 
         /**
          * Constructs a new Builder with the defaults:
@@ -3305,45 +3396,38 @@
         }
 
         private RemoteViews applyStandardTemplate(int resId) {
-            return applyStandardTemplate(resId, true /* hasProgress */);
+            return applyStandardTemplate(resId, mParams.reset().fillTextsFrom(this));
         }
 
         /**
          * @param hasProgress whether the progress bar should be shown and set
          */
         private RemoteViews applyStandardTemplate(int resId, boolean hasProgress) {
-            final Bundle ex = mN.extras;
-
-            CharSequence title = processLegacyText(ex.getCharSequence(EXTRA_TITLE));
-            CharSequence text = processLegacyText(ex.getCharSequence(EXTRA_TEXT));
-            return applyStandardTemplate(resId, hasProgress, title, text);
+            return applyStandardTemplate(resId, mParams.reset().hasProgress(hasProgress)
+                    .fillTextsFrom(this));
         }
 
-        /**
-         * @param hasProgress whether the progress bar should be shown and set
-         */
-        private RemoteViews applyStandardTemplate(int resId, boolean hasProgress,
-                CharSequence title, CharSequence text) {
+        private RemoteViews applyStandardTemplate(int resId, StandardTemplateParams p) {
             RemoteViews contentView = new BuilderRemoteViews(mContext.getApplicationInfo(), resId);
 
             resetStandardTemplate(contentView);
 
             final Bundle ex = mN.extras;
 
-            bindNotificationHeader(contentView);
+            bindNotificationHeader(contentView, p.ambient);
             bindLargeIcon(contentView);
-            boolean showProgress = handleProgressBar(hasProgress, contentView, ex);
-            if (title != null) {
+            boolean showProgress = handleProgressBar(p.hasProgress, contentView, ex);
+            if (p.title != null) {
                 contentView.setViewVisibility(R.id.title, View.VISIBLE);
-                contentView.setTextViewText(R.id.title, title);
+                contentView.setTextViewText(R.id.title, p.title);
                 contentView.setViewLayoutWidth(R.id.title, showProgress
                         ? ViewGroup.LayoutParams.WRAP_CONTENT
                         : ViewGroup.LayoutParams.MATCH_PARENT);
             }
-            if (text != null) {
+            if (p.text != null) {
                 int textId = showProgress ? com.android.internal.R.id.text_line_1
                         : com.android.internal.R.id.text;
-                contentView.setTextViewText(textId, text);
+                contentView.setTextViewText(textId, p.text);
                 contentView.setViewVisibility(textId, View.VISIBLE);
             }
 
@@ -3405,13 +3489,16 @@
             }
         }
 
-        private void bindNotificationHeader(RemoteViews contentView) {
-            bindSmallIcon(contentView);
-            bindHeaderAppName(contentView);
-            bindHeaderText(contentView);
-            bindHeaderChronometerAndTime(contentView);
-            bindExpandButton(contentView);
-            bindProfileBadge(contentView);
+        private void bindNotificationHeader(RemoteViews contentView, boolean ambient) {
+            bindSmallIcon(contentView, ambient);
+            bindHeaderAppName(contentView, ambient);
+            if (!ambient) {
+                // Ambient view does not have these
+                bindHeaderText(contentView);
+                bindHeaderChronometerAndTime(contentView);
+                bindExpandButton(contentView);
+                bindProfileBadge(contentView);
+            }
         }
 
         private void bindExpandButton(RemoteViews contentView) {
@@ -3494,19 +3581,20 @@
 
             return String.valueOf(name);
         }
-        private void bindHeaderAppName(RemoteViews contentView) {
+        private void bindHeaderAppName(RemoteViews contentView, boolean ambient) {
             contentView.setTextViewText(R.id.app_name_text, loadHeaderAppName());
-            contentView.setTextColor(R.id.app_name_text, resolveContrastColor());
+            contentView.setTextColor(R.id.app_name_text,
+                    ambient ? resolveAmbientColor() : resolveContrastColor());
         }
 
-        private void bindSmallIcon(RemoteViews contentView) {
+        private void bindSmallIcon(RemoteViews contentView, boolean ambient) {
             if (mN.mSmallIcon == null && mN.icon != 0) {
                 mN.mSmallIcon = Icon.createWithResource(mContext, mN.icon);
             }
             contentView.setImageViewIcon(R.id.icon, mN.mSmallIcon);
             contentView.setDrawableParameters(R.id.icon, false /* targetBackground */,
                     -1 /* alpha */, -1 /* colorFilter */, null /* mode */, mN.iconLevel);
-            processSmallIconColor(mN.mSmallIcon, contentView);
+            processSmallIconColor(mN.mSmallIcon, contentView, ambient);
         }
 
         /**
@@ -3535,27 +3623,26 @@
         }
 
         private RemoteViews applyStandardTemplateWithActions(int layoutId) {
-            final Bundle ex = mN.extras;
-
-            CharSequence title = processLegacyText(ex.getCharSequence(EXTRA_TITLE));
-            CharSequence text = processLegacyText(ex.getCharSequence(EXTRA_TEXT));
-            return applyStandardTemplateWithActions(layoutId, true /* hasProgress */, title, text);
+            return applyStandardTemplateWithActions(layoutId, mParams.reset().fillTextsFrom(this));
         }
 
-        private RemoteViews applyStandardTemplateWithActions(int layoutId, boolean hasProgress,
-                CharSequence title, CharSequence text) {
-            RemoteViews big = applyStandardTemplate(layoutId, hasProgress, title, text);
+        private RemoteViews applyStandardTemplateWithActions(int layoutId,
+            StandardTemplateParams p) {
+            RemoteViews big = applyStandardTemplate(layoutId, p);
 
             resetStandardTemplateWithActions(big);
 
             boolean validRemoteInput = false;
 
             int N = mActions.size();
-            boolean emphazisedMode = mN.fullScreenIntent != null;
+            boolean emphazisedMode = mN.fullScreenIntent != null && !p.ambient;
             big.setBoolean(R.id.actions, "setEmphasizedMode", emphazisedMode);
             if (N > 0) {
                 big.setViewVisibility(R.id.actions_container, View.VISIBLE);
                 big.setViewVisibility(R.id.actions, View.VISIBLE);
+                if (p.ambient) {
+                    big.setInt(R.id.actions, "setBackgroundColor", Color.TRANSPARENT);
+                }
                 big.setViewLayoutMarginBottomDimen(R.id.notification_action_list_margin_target,
                         R.dimen.notification_action_list_height);
                 if (N>MAX_ACTION_BUTTONS) N=MAX_ACTION_BUTTONS;
@@ -3564,7 +3651,7 @@
                     validRemoteInput |= hasValidRemoteInput(action);
 
                     final RemoteViews button = generateActionButton(action, emphazisedMode,
-                            i % 2 != 0);
+                            i % 2 != 0, p.ambient);
                     big.addView(R.id.actions, button);
                 }
             } else {
@@ -3572,7 +3659,7 @@
             }
 
             CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
-            if (validRemoteInput && replyText != null
+            if (!p.ambient && validRemoteInput && replyText != null
                     && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) {
                 big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE);
                 big.setTextViewText(R.id.notification_material_reply_text_1, replyText[0]);
@@ -3657,10 +3744,22 @@
             RemoteViews header = new BuilderRemoteViews(mContext.getApplicationInfo(),
                     R.layout.notification_template_header);
             resetNotificationHeader(header);
-            bindNotificationHeader(header);
+            bindNotificationHeader(header, false /* ambient */);
             return header;
         }
 
+        /**
+         * Construct a RemoteViews for the ambient version of the notification.
+         *
+         * @hide
+         */
+        public RemoteViews makeAmbientNotification() {
+            RemoteViews ambient = applyStandardTemplateWithActions(
+                    R.layout.notification_template_material_ambient,
+                    mParams.reset().fillTextsFrom(this).hasProgress(false).ambient(true));
+            return ambient;
+        }
+
         private void hideLine1Text(RemoteViews result) {
             if (result != null) {
                 result.setViewVisibility(R.id.text_line_1, View.GONE);
@@ -3730,7 +3829,7 @@
 
 
         private RemoteViews generateActionButton(Action action, boolean emphazisedMode,
-                boolean oddAction) {
+                boolean oddAction, boolean ambient) {
             final boolean tombstone = (action.actionIntent == null);
             RemoteViews button = new BuilderRemoteViews(mContext.getApplicationInfo(),
                     emphazisedMode ? getEmphasizedActionLayoutResource()
@@ -3768,7 +3867,8 @@
             } else {
                 button.setTextViewText(R.id.action0, processLegacyText(action.title));
                 if (mN.color != COLOR_DEFAULT) {
-                    button.setTextColor(R.id.action0, resolveContrastColor());
+                    button.setTextColor(R.id.action0,
+                            ambient ? resolveAmbientColor() : resolveContrastColor());
                 }
             }
             return button;
@@ -3899,15 +3999,17 @@
         /**
          * Apply any necessariy colors to the small icon
          */
-        private void processSmallIconColor(Icon smallIcon, RemoteViews contentView) {
+        private void processSmallIconColor(Icon smallIcon, RemoteViews contentView,
+                boolean ambient) {
             boolean colorable = !isLegacy() || getColorUtil().isGrayscaleIcon(mContext, smallIcon);
+            int color = ambient ? resolveAmbientColor() : resolveContrastColor();
             if (colorable) {
-                contentView.setDrawableParameters(R.id.icon, false, -1, resolveContrastColor(),
+                contentView.setDrawableParameters(R.id.icon, false, -1, color,
                         PorterDuff.Mode.SRC_ATOP, -1);
 
             }
             contentView.setInt(R.id.notification_header, "setOriginalIconColor",
-                    colorable ? resolveContrastColor() : NotificationHeaderView.NO_COLOR);
+                    colorable ? color : NotificationHeaderView.NO_COLOR);
         }
 
         /**
@@ -3940,6 +4042,16 @@
             return mCachedContrastColor = contrasted;
         }
 
+        int resolveAmbientColor() {
+            if (mCachedAmbientColorIsFor == mN.color && mCachedAmbientColorIsFor != COLOR_INVALID) {
+                return mCachedAmbientColor;
+            }
+            final int contrasted = NotificationColorUtil.resolveAmbientColor(mContext, mN.color);
+
+            mCachedAmbientColorIsFor = mN.color;
+            return mCachedAmbientColor = contrasted;
+        }
+
         /**
          * Apply the unstyled operations and return a new {@link Notification} object.
          * @hide
@@ -4835,10 +4947,8 @@
                     ? null
                     : mConversationTitle != null ? makeMessageLine(m) : m.mText;
 
-            return mBuilder.applyStandardTemplate(mBuilder.getBaseLayoutResource(),
-                    false /* hasProgress */,
-                    title,
-                    text);
+            return mBuilder.applyStandardTemplateWithActions(mBuilder.getBaseLayoutResource(),
+                    mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
         }
 
         private Message findLatestIncomingMessage() {
@@ -4880,16 +4990,14 @@
                 }
                 RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
                         mBuilder.getBigTextLayoutResource(),
-                        false /* progress */, bigTitle, null /* text */);
+                        mBuilder.mParams.reset().hasProgress(false).title(bigTitle).text(null));
                 BigTextStyle.applyBigTextContentView(mBuilder, contentView, text);
                 return contentView;
             }
 
             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
                     mBuilder.getMessagingLayoutResource(),
-                    false /* hasProgress */,
-                    title,
-                    null /* text */);
+                    mBuilder.mParams.reset().hasProgress(false).title(title).text(null));
 
             int[] rowIds = {R.id.inbox_text0, R.id.inbox_text1, R.id.inbox_text2, R.id.inbox_text3,
                     R.id.inbox_text4, R.id.inbox_text5, R.id.inbox_text6};
@@ -4959,9 +5067,7 @@
                     : mConversationTitle != null ? makeMessageLine(m) : m.mText;
 
             return mBuilder.applyStandardTemplateWithActions(mBuilder.getBigBaseLayoutResource(),
-                    false /* hasProgress */,
-                    title,
-                    text);
+                    mBuilder.mParams.reset().hasProgress(false).title(title).text(text));
         }
 
         private static TextAppearanceSpan makeFontColorSpan(int color) {
@@ -6948,6 +7054,142 @@
     }
 
     /**
+     * <p>Helper class to add Android TV extensions to notifications. To create a notification
+     * with a TV extension:
+     *
+     * <ol>
+     *  <li>Create an {@link Notification.Builder}, setting any desired properties.
+     *  <li>Create a {@link TvExtender}.
+     *  <li>Set TV-specific properties using the {@code set} methods of
+     *  {@link TvExtender}.
+     *  <li>Call {@link Notification.Builder#extend(Notification.Extender)}
+     *  to apply the extension to a notification.
+     * </ol>
+     *
+     * <pre class="prettyprint">
+     * Notification notification = new Notification.Builder(context)
+     *         ...
+     *         .extend(new TvExtender()
+     *                 .set*(...))
+     *         .build();
+     * </pre>
+     *
+     * <p>TV extensions can be accessed on an existing notification by using the
+     * {@code TvExtender(Notification)} constructor, and then using the {@code get} methods
+     * to access values.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final class TvExtender implements Extender {
+        private static final String TAG = "TvExtender";
+
+        private static final String EXTRA_TV_EXTENDER = "android.tv.EXTENSIONS";
+        private static final String EXTRA_FLAGS = "flags";
+        private static final String EXTRA_CONTENT_INTENT = "content_intent";
+        private static final String EXTRA_DELETE_INTENT = "delete_intent";
+
+        // Flags bitwise-ored to mFlags
+        private static final int FLAG_AVAILABLE_ON_TV = 0x1;
+
+        private int mFlags;
+        private PendingIntent mContentIntent;
+        private PendingIntent mDeleteIntent;
+
+        /**
+         * Create a {@link TvExtender} with default options.
+         */
+        public TvExtender() {
+            mFlags = FLAG_AVAILABLE_ON_TV;
+        }
+
+        /**
+         * Create a {@link TvExtender} from the TvExtender options of an existing Notification.
+         *
+         * @param notif The notification from which to copy options.
+         */
+        public TvExtender(Notification notif) {
+            Bundle bundle = notif.extras == null ?
+                null : notif.extras.getBundle(EXTRA_TV_EXTENDER);
+            if (bundle != null) {
+                mFlags = bundle.getInt(EXTRA_FLAGS);
+                mContentIntent = bundle.getParcelable(EXTRA_CONTENT_INTENT);
+                mDeleteIntent = bundle.getParcelable(EXTRA_DELETE_INTENT);
+            }
+        }
+
+        /**
+         * Apply a TV extension to a notification that is being built. This is typically called by
+         * the {@link Notification.Builder#extend(Notification.Extender)}
+         * method of {@link Notification.Builder}.
+         */
+        @Override
+        public Notification.Builder extend(Notification.Builder builder) {
+            Bundle bundle = new Bundle();
+
+            bundle.putInt(EXTRA_FLAGS, mFlags);
+            if (mContentIntent != null) {
+                bundle.putParcelable(EXTRA_CONTENT_INTENT, mContentIntent);
+            }
+
+            if (mDeleteIntent != null) {
+                bundle.putParcelable(EXTRA_DELETE_INTENT, mDeleteIntent);
+            }
+
+            builder.getExtras().putBundle(EXTRA_TV_EXTENDER, bundle);
+            return builder;
+        }
+
+        /**
+         * Returns true if this notification should be shown on TV. This method return true
+         * if the notification was extended with a TvExtender.
+         */
+        public boolean isAvailableOnTv() {
+            return (mFlags & FLAG_AVAILABLE_ON_TV) != 0;
+        }
+
+        /**
+         * Supplies a {@link PendingIntent} to be sent when the notification is selected on TV.
+         * If provided, it is used instead of the content intent specified
+         * at the level of Notification.
+         */
+        public TvExtender setContentIntent(PendingIntent intent) {
+            mContentIntent = intent;
+            return this;
+        }
+
+        /**
+         * Returns the TV-specific content intent.  If this method returns null, the
+         * main content intent on the notification should be used.
+         *
+         * @see {@link Notification#contentIntent}
+         */
+        public PendingIntent getContentIntent() {
+            return mContentIntent;
+        }
+
+        /**
+         * Supplies a {@link PendingIntent} to send when the notification is cleared explicitly
+         * by the user on TV.  If provided, it is used instead of the delete intent specified
+         * at the level of Notification.
+         */
+        public TvExtender setDeleteIntent(PendingIntent intent) {
+            mDeleteIntent = intent;
+            return this;
+        }
+
+        /**
+         * Returns the TV-specific delete intent.  If this method returns null, the
+         * main delete intent on the notification should be used.
+         *
+         * @see {@link Notification#deleteIntent}
+         */
+        public PendingIntent getDeleteIntent() {
+            return mDeleteIntent;
+        }
+    }
+
+    /**
      * Get an array of Notification objects from a parcelable array bundle field.
      * Update the bundle to have a typed array so fetches in the future don't need
      * to do an array copy.
@@ -6982,4 +7224,46 @@
             return brv;
         }
     }
+
+    private static class StandardTemplateParams {
+        boolean hasProgress = true;
+        boolean ambient = false;
+        CharSequence title;
+        CharSequence text;
+
+        final StandardTemplateParams reset() {
+            hasProgress = true;
+            ambient = false;
+            title = null;
+            text = null;
+            return this;
+        }
+
+        final StandardTemplateParams hasProgress(boolean hasProgress) {
+            this.hasProgress = hasProgress;
+            return this;
+        }
+
+        final StandardTemplateParams title(CharSequence title) {
+            this.title = title;
+            return this;
+        }
+
+        final StandardTemplateParams text(CharSequence text) {
+            this.text = text;
+            return this;
+        }
+
+        final StandardTemplateParams ambient(boolean ambient) {
+            this.ambient = ambient;
+            return this;
+        }
+
+        final StandardTemplateParams fillTextsFrom(Builder b) {
+            Bundle extras = b.mN.extras;
+            title = b.processLegacyText(extras.getCharSequence(EXTRA_TITLE));
+            text = b.processLegacyText(extras.getCharSequence(EXTRA_TEXT));
+            return this;
+        }
+    }
 }
diff --git a/core/java/android/app/RemoteInput.java b/core/java/android/app/RemoteInput.java
index 11420c5..d1dc859 100644
--- a/core/java/android/app/RemoteInput.java
+++ b/core/java/android/app/RemoteInput.java
@@ -19,9 +19,14 @@
 import android.content.ClipData;
 import android.content.ClipDescription;
 import android.content.Intent;
+import android.net.Uri;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.ArraySet;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
 
 /**
  * A {@code RemoteInput} object specifies input to be collected from a user to be passed along with
@@ -61,9 +66,13 @@
     /** Label used to denote the clip data type used for remote input transport */
     public static final String RESULTS_CLIP_LABEL = "android.remoteinput.results";
 
-    /** Extra added to a clip data intent object to hold the results bundle. */
+    /** Extra added to a clip data intent object to hold the text results bundle. */
     public static final String EXTRA_RESULTS_DATA = "android.remoteinput.resultsData";
 
+    /** Extra added to a clip data intent object to hold the data results bundle. */
+    private static final String EXTRA_DATA_TYPE_RESULTS_DATA =
+            "android.remoteinput.dataTypeResultsData";
+
     // Flags bitwise-ored to mFlags
     private static final int FLAG_ALLOW_FREE_FORM_INPUT = 0x1;
 
@@ -75,14 +84,16 @@
     private final CharSequence[] mChoices;
     private final int mFlags;
     private final Bundle mExtras;
+    private final ArraySet<String> mAllowedDataTypes;
 
     private RemoteInput(String resultKey, CharSequence label, CharSequence[] choices,
-            int flags, Bundle extras) {
+            int flags, Bundle extras, ArraySet<String> allowedDataTypes) {
         this.mResultKey = resultKey;
         this.mLabel = label;
         this.mChoices = choices;
         this.mFlags = flags;
         this.mExtras = extras;
+        this.mAllowedDataTypes = allowedDataTypes;
     }
 
     /**
@@ -107,6 +118,21 @@
         return mChoices;
     }
 
+    public Set<String> getAllowedDataTypes() {
+        return mAllowedDataTypes;
+    }
+
+    /**
+     * Returns true if the input only accepts data, meaning {@link #getAllowFreeFormInput}
+     * is false, {@link #getChoices} is null or empty, and {@link #getAllowedDataTypes is
+     * non-null and not empty.
+     */
+    public boolean isDataOnly() {
+        return !getAllowFreeFormInput()
+                && (getChoices() == null || getChoices().length == 0)
+                && !getAllowedDataTypes().isEmpty();
+    }
+
     /**
      * Get whether or not users can provide an arbitrary value for
      * input. If you set this to {@code false}, users must select one of the
@@ -133,6 +159,7 @@
         private CharSequence[] mChoices;
         private int mFlags = DEFAULT_FLAGS;
         private Bundle mExtras = new Bundle();
+        private final ArraySet<String> mAllowedDataTypes = new ArraySet<>();
 
         /**
          * Create a builder object for {@link RemoteInput} objects.
@@ -177,14 +204,34 @@
         /**
          * Specifies whether the user can provide arbitrary values.
          *
-         * @param allowFreeFormInput The default is {@code true}.
-         *         If you specify {@code false}, you must provide a non-null
-         *         and non-empty array to {@link #setChoices} or an
+         * @param mimeType A mime type that results are allowed to come in.
+         *         Be aware that text results (see {@link #setAllowFreeFormInput}
+         *         are allowed by default. If you do not want text results you will have to
+         *         pass false to {@code setAllowFreeFormInput}.
+         * @param doAllow Whether the mime type should be allowed or not.
+         * @return this object for method chaining
+         */
+        public Builder setAllowDataType(String mimeType, boolean doAllow) {
+            if (doAllow) {
+                mAllowedDataTypes.add(mimeType);
+            } else {
+                mAllowedDataTypes.remove(mimeType);
+            }
+            return this;
+        }
+
+        /**
+         * Specifies whether the user can provide arbitrary text values.
+         *
+         * @param allowFreeFormTextInput The default is {@code true}.
+         *         If you specify {@code false}, you must either provide a non-null
+         *         and non-empty array to {@link #setChoices}, or enable a data result
+         *         in {@code setAllowDataType}. Otherwise an
          *         {@link IllegalArgumentException} is thrown.
          * @return this object for method chaining
          */
-        public Builder setAllowFreeFormInput(boolean allowFreeFormInput) {
-            setFlag(mFlags, allowFreeFormInput);
+        public Builder setAllowFreeFormInput(boolean allowFreeFormTextInput) {
+            setFlag(mFlags, allowFreeFormTextInput);
             return this;
         }
 
@@ -224,7 +271,8 @@
          * object.
          */
         public RemoteInput build() {
-            return new RemoteInput(mResultKey, mLabel, mChoices, mFlags, mExtras);
+            return new RemoteInput(
+                    mResultKey, mLabel, mChoices, mFlags, mExtras, mAllowedDataTypes);
         }
     }
 
@@ -234,32 +282,68 @@
         mChoices = in.readCharSequenceArray();
         mFlags = in.readInt();
         mExtras = in.readBundle();
+        mAllowedDataTypes = (ArraySet<String>) in.readArraySet(null);
     }
 
     /**
-     * Get the remote input results bundle from an intent. The returned Bundle will
-     * contain a key/value for every result key populated by remote input collector.
-     * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value.
+     * Similar as {@link #getResultsFromIntent} but retrieves data results for a
+     * specific RemoteInput result. To retrieve a value use:
+     * <pre>
+     * {@code
+     * Map<String, Uri> results =
+     *     RemoteInput.getDataResultsFromIntent(intent, REMOTE_INPUT_KEY);
+     * if (results != null) {
+     *   Uri data = results.get(MIME_TYPE_OF_INTEREST);
+     * }
+     * }
+     * </pre>
+     * @param intent The intent object that fired in response to an action or content intent
+     *               which also had one or more remote input requested.
+     * @param remoteInputResultKey The result key for the RemoteInput you want results for.
+     */
+    public static Map<String, Uri> getDataResultsFromIntent(
+            Intent intent, String remoteInputResultKey) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            return null;
+        }
+        Map<String, Uri> results = new HashMap<>();
+        Bundle extras = clipDataIntent.getExtras();
+        for (String key : extras.keySet()) {
+          if (key.startsWith(EXTRA_DATA_TYPE_RESULTS_DATA)) {
+              String mimeType = key.substring(EXTRA_DATA_TYPE_RESULTS_DATA.length());
+              if (mimeType == null || mimeType.isEmpty()) {
+                  continue;
+              }
+              Bundle bundle = clipDataIntent.getBundleExtra(key);
+              String uriStr = bundle.getString(remoteInputResultKey);
+              if (uriStr == null || uriStr.isEmpty()) {
+                  continue;
+              }
+              results.put(mimeType, Uri.parse(uriStr));
+          }
+        }
+        return results.isEmpty() ? null : results;
+    }
+
+    /**
+     * Get the remote input text results bundle from an intent. The returned Bundle will
+     * contain a key/value for every result key populated with text by remote input collector.
+     * Use the {@link Bundle#getCharSequence(String)} method to retrieve a value. For non-text
+     * results use {@link #getDataResultsFromIntent}.
      * @param intent The intent object that fired in response to an action or content intent
      *               which also had one or more remote input requested.
      */
     public static Bundle getResultsFromIntent(Intent intent) {
-        ClipData clipData = intent.getClipData();
-        if (clipData == null) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
             return null;
         }
-        ClipDescription clipDescription = clipData.getDescription();
-        if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
-            return null;
-        }
-        if (clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) {
-            return clipData.getItemAt(0).getIntent().getExtras().getParcelable(EXTRA_RESULTS_DATA);
-        }
-        return null;
+        return clipDataIntent.getExtras().getParcelable(EXTRA_RESULTS_DATA);
     }
 
     /**
-     * Populate an intent object with the results gathered from remote input. This method
+     * Populate an intent object with the text results gathered from remote input. This method
      * should only be called by remote input collection services when sending results to a
      * pending intent.
      * @param remoteInputs The remote inputs for which results are being provided
@@ -267,20 +351,61 @@
      *               field of the intent will be modified to contain the results.
      * @param results A bundle holding the remote input results. This bundle should
      *                be populated with keys matching the result keys specified in
-     *                {@code remoteInputs} with values being the result per key.
+     *                {@code remoteInputs} with values being the CharSequence results per key.
      */
     public static void addResultsToIntent(RemoteInput[] remoteInputs, Intent intent,
             Bundle results) {
-        Bundle resultsBundle = new Bundle();
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            clipDataIntent = new Intent();  // First time we've added a result.
+        }
+        Bundle resultsBundle = clipDataIntent.getBundleExtra(EXTRA_RESULTS_DATA);
+        if (resultsBundle == null) {
+            resultsBundle = new Bundle();
+        }
         for (RemoteInput remoteInput : remoteInputs) {
             Object result = results.get(remoteInput.getResultKey());
             if (result instanceof CharSequence) {
                 resultsBundle.putCharSequence(remoteInput.getResultKey(), (CharSequence) result);
             }
         }
-        Intent clipIntent = new Intent();
-        clipIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle);
-        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipIntent));
+        clipDataIntent.putExtra(EXTRA_RESULTS_DATA, resultsBundle);
+        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
+    }
+
+    /**
+     * Same as {@link #addResultsToIntent} but for setting data results.
+     * @param remoteInput The remote input for which results are being provided
+     * @param intent The intent to add remote input results to. The {@link ClipData}
+     *               field of the intent will be modified to contain the results.
+     * @param results A map of mime type to the Uri result for that mime type.
+     */
+    public static void addDataResultToIntent(RemoteInput remoteInput, Intent intent,
+            Map<String, Uri> results) {
+        Intent clipDataIntent = getClipDataIntentFromIntent(intent);
+        if (clipDataIntent == null) {
+            clipDataIntent = new Intent();  // First time we've added a result.
+        }
+        for (Map.Entry<String, Uri> entry : results.entrySet()) {
+            String mimeType = entry.getKey();
+            Uri uri = entry.getValue();
+            if (mimeType == null) {
+                continue;
+            }
+            Bundle resultsBundle =
+                    clipDataIntent.getBundleExtra(getExtraResultsKeyForData(mimeType));
+            if (resultsBundle == null) {
+                resultsBundle = new Bundle();
+            }
+            resultsBundle.putString(remoteInput.getResultKey(), uri.toString());
+
+            clipDataIntent.putExtra(getExtraResultsKeyForData(mimeType), resultsBundle);
+        }
+        intent.setClipData(ClipData.newIntent(RESULTS_CLIP_LABEL, clipDataIntent));
+    }
+
+    private static String getExtraResultsKeyForData(String mimeType) {
+        return EXTRA_DATA_TYPE_RESULTS_DATA + mimeType;
     }
 
     @Override
@@ -295,6 +420,7 @@
         out.writeCharSequenceArray(mChoices);
         out.writeInt(mFlags);
         out.writeBundle(mExtras);
+        out.writeArraySet(mAllowedDataTypes);
     }
 
     public static final Creator<RemoteInput> CREATOR = new Creator<RemoteInput>() {
@@ -308,4 +434,19 @@
             return new RemoteInput[size];
         }
     };
+
+    private static Intent getClipDataIntentFromIntent(Intent intent) {
+        ClipData clipData = intent.getClipData();
+        if (clipData == null) {
+            return null;
+        }
+        ClipDescription clipDescription = clipData.getDescription();
+        if (!clipDescription.hasMimeType(ClipDescription.MIMETYPE_TEXT_INTENT)) {
+            return null;
+        }
+        if (!clipDescription.getLabel().equals(RESULTS_CLIP_LABEL)) {
+            return null;
+        }
+        return clipData.getItemAt(0).getIntent();
+    }
 }
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index ad5e69b..fd766bf 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.app.ActivityManager.TaskSnapshot;
 import android.content.ComponentName;
 import android.os.RemoteException;
 
@@ -78,4 +79,9 @@
     @Override
     public void onTaskProfileLocked(int taskId, int userId) {
     }
+
+    @Override
+    public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot)
+            throws RemoteException {
+    }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 6d6ada6..2701698 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6332,7 +6332,7 @@
      * @see #setPermissionGrantState(ComponentName, String, String, int)
      * @see PackageManager#checkPermission(String, String)
      */
-    public int getPermissionGrantState(@NonNull ComponentName admin, String packageName,
+    public int getPermissionGrantState(@Nullable ComponentName admin, String packageName,
             String permission) {
         throwIfParentInstance("getPermissionGrantState");
         try {
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 12f6442..4ffc6f9 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -1081,10 +1081,9 @@
             @Nullable Bundle queryArgs, @Nullable CancellationSignal cancellationSignal) {
         queryArgs = queryArgs != null ? queryArgs : Bundle.EMPTY;
 
+        // if client doesn't supply an SQL sort order argument, attempt to build one from
+        // QUERY_ARG_SORT* arguments.
         String sortClause = queryArgs.getString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER);
-
-        // if client didn't explicitly supply and sql sort order argument, we try to build
-        // one from sort columns if present.
         if (sortClause == null && queryArgs.containsKey(ContentResolver.QUERY_ARG_SORT_COLUMNS)) {
             sortClause = ContentResolver.createSqlSortClause(queryArgs);
         }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 80556bd..4480b41 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -211,9 +211,9 @@
      * should use standard placeholder notation to represent values in a selection string,
      * then supply a corresponding value in {@value #QUERY_ARG_SQL_SELECTION_ARGS}.
      *
-     * <p><b>Clients targeting Android O or higher are strongly encourage to use structured
-     * query arguments in lieu of opaque SQL query clauses.</b> See:
-     * {@link #QUERY_ARG_SORT_COLUMNS}, {@link #QUERY_ARG_SORT_DIRECTION}, and
+     * <p><b>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
+     * encourage to use structured query arguments in lieu of opaque SQL query clauses.</b>
+     * See: {@link #QUERY_ARG_SORT_COLUMNS}, {@link #QUERY_ARG_SORT_DIRECTION}, and
      * {@link #QUERY_ARG_SORT_COLLATION}.
      */
     public static final String QUERY_ARG_SQL_SELECTION = "android:query-sql-selection";
@@ -226,9 +226,9 @@
      * should use standard placeholder notation to represent values in a selection string,
      * then supply a corresponding value in {@value #QUERY_ARG_SQL_SELECTION_ARGS}.
      *
-     * <p><b>Clients targeting Android O or higher are strongly encourage to use structured
-     * query arguments in lieu of opaque SQL query clauses.</b> See:
-     * {@link #QUERY_ARG_SORT_COLUMNS}, {@link #QUERY_ARG_SORT_DIRECTION}, and
+     * <p><b>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
+     * encourage to use structured query arguments in lieu of opaque SQL query clauses.</b>
+     * See: {@link #QUERY_ARG_SORT_COLUMNS}, {@link #QUERY_ARG_SORT_DIRECTION}, and
      * {@link #QUERY_ARG_SORT_COLLATION}.
      */
     public static final String QUERY_ARG_SQL_SELECTION_ARGS = "android:query-sql-selection-args";
@@ -238,25 +238,30 @@
      * passed to {@link ContentProvider#query(Uri, String[], Bundle, CancellationSignal)}
      * when called by a legacy client.
      *
-     * <p><b>Clients targeting Android O or higher are strongly encourage to use structured
-     * query arguments in lieu of opaque SQL query clauses.</b> See:
-     * {@link #QUERY_ARG_SORT_COLUMNS}, {@link #QUERY_ARG_SORT_DIRECTION}, and
+     * <p><b>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
+     * encourage to use structured query arguments in lieu of opaque SQL query clauses.</b>
+     * See: {@link #QUERY_ARG_SORT_COLUMNS}, {@link #QUERY_ARG_SORT_DIRECTION}, and
      * {@link #QUERY_ARG_SORT_COLLATION}.
      */
     public static final String QUERY_ARG_SQL_SORT_ORDER = "android:query-sql-sort-order";
 
     /**
-     * Identifies the list columns against which to sort results.
+     * Specifies the list of columns against which to sort results. When first column values
+     * are identical, records are then sorted based on second column values, and so on.
      *
      * <p>Columns present in this list must also be included in the projection
      * supplied to {@link ContentResolver#query(Uri, String[], Bundle, CancellationSignal)}.
      *
-     * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
-     * encouraged to include an entry in Cursor extras under this same key as an indication
-     * to the client that column sorting was honored.
+     * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher:
      *
-     * <p>QUERY_SORT* values are exclusive from QUERY_ARG_SQL* arguments.
-     * When any QUERY_SORT arguments are present, any QUERY_ARG_SQL* values will be ignored.
+     * <li>When supplying data using a ContentProvider, it is strongly recommended that
+     * an entry be included in the {@link Cursor} extras {@link Bundle} under this same key
+     * (@link QUERY_ARG_SORT_COLUMNS}) to indicate which column sorting was applied
+     * to the recordset, if any.
+     *
+     * <li>When querying a provider, where no QUERY_ARG_SQL* otherwise exists in the
+     * arguments {@link Bundle}, the Content framework will attempt to synthesize
+     * an QUERY_ARG_SQL* argument using the corresponding QUERY_ARG_SORT* values.
      */
     public static final String QUERY_ARG_SORT_COLUMNS = "android:query-sort-columns";
 
@@ -264,9 +269,16 @@
      * Specifies desired sort order. When unspecified a provider may provide a default
      * sort direction, or choose to return unsorted results.
      *
-     * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
-     * encouraged to include an entry in Cursor extras under this same key as an indication
-     * to the client that sort direction was honored.
+     * <p>Apps targeting {@link android.os.Build.VERSION_CODES#O} or higher:
+     *
+     * <li>When supplying data using a ContentProvider, it is strongly recommended that
+     * an entry be included in the {@link Cursor} extras {@link Bundle} under this same key
+     * (@link QUERY_ARG_SORT_DIRECTION}) to indicate that sort direction was applied
+     * to the recordset.
+     *
+     * <li>When querying a provider, where no QUERY_ARG_SQL* otherwise exists in the
+     * arguments {@link Bundle}, the Content framework will attempt to synthesize
+     * an QUERY_ARG_SQL* argument using the corresponding QUERY_ARG_SORT* values.
      *
      * @see #QUERY_SORT_DIRECTION_ASCENDING
      * @see #QUERY_SORT_DIRECTION_DESCENDING
@@ -280,11 +292,17 @@
      * <p>Providers may provide their own collators. When selecting a custom collator
      * the value will be determined by the Provider.
      *
-     * <p>apps targeting {@link android.os.Build.VERSION_CODES#O} or higher are strongly
-     * encouraged to include an entry in Cursor extras under this same key as an indication
-     * to the client that collation was honored.
+     * <li>When supplying data using a ContentProvider, it is strongly recommended that
+     * an entry be included in the {@link Cursor} extras {@link Bundle} under this same key
+     * (@link QUERY_ARG_SORT_COLLATION}) to indicate that sort collation was applied
+     * to the recordset.
      *
-     * @see #QUERY_COLLATOR_MODE_NOCASE
+     * <p>When querying a provider, where no QUERY_ARG_SQL* otherwise exists in the
+     * arguments {@link Bundle}, the Content framework will attempt to synthesize
+     * an QUERY_ARG_SQL* argument using the corresponding QUERY_ARG_SORT* values.
+     *
+     * @see java.text.Collator#PRIMARY, java.text.Collator#SECONDARY,
+     *     java.text.Collator#TERTIARY, and java.text.Collator#IDENTICAL.
      */
     public static final String QUERY_ARG_SORT_COLLATION = "android:query-sort-collation";
 
@@ -312,6 +330,42 @@
     public @interface QueryCollator {}
 
     /**
+     * Specifies the offset from which to load a recordset. Records prior to this
+     * position should be omitted from results.
+     *
+     * <p>Providers are recommended to create a content notification Uri
+     * that encapsulates QUERY_ARG_OFFSET and QUERY_ARG_LIMITS values reflected
+     * in the recordset. This will allow a provider to notify clients of changes
+     * to an individual recordset.
+     */
+    public static final String QUERY_ARG_OFFSET = "android:query-page-offset";
+
+    /**
+     * Specifies the max number of records to include in a recordset with respect
+     * to the starting offset, which by default is 0. Records beyond starting offset + limit
+     * should be omitted from results.
+     *
+     * <p>Providers are recommended to create a content notification Uri
+     * that encapsulates QUERY_ARG_OFFSET and QUERY_ARG_LIMITS values reflected
+     * in the recordset. This will allow a provider to notify clients of changes
+     * to an individual recordset.
+     */
+    public static final String QUERY_ARG_LIMIT = "android:query-page-limit";
+
+    /**
+     * Added to {@link Cursor} extras {@link Bundle} to indicate size of the
+     * full, un-offset, un-limited recordset.
+     *
+     * <p>When full size of the recordset is unknown a provider may return -1
+     * to indicate this.
+     *
+     * <p>Providers having returned -1 in a previous query are recommended to
+     * send content change notification once (if) full recordset size becomes
+     * known.
+     */
+    public static final String QUERY_RESULT_SIZE = "android:query-result-size";
+
+    /**
      * This is the Android platform's base MIME type for a content: URI
      * containing a Cursor of a single item.  Applications should use this
      * as the base type along with their own sub-type of their content: URIs
@@ -2919,10 +2973,16 @@
     /**
      * Returns structured sort args formatted as an SQL sort clause.
      *
-     * Collator clauses are not included as column information is unknown, and
-     * collate clauses should only be included on text fields.
+     * NOTE: Collator clauses are suitable for use with non text fields. We might
+     * choose to omit any collation clause since we don't know the underlying
+     * type of data to be collated. Imperical testing shows that sqlite3 doesn't
+     * appear to care much about the presence of collate clauses in queries
+     * when ordering by numeric fields. For this reason we include collate
+     * clause unilaterally when {@link #QUERY_ARG_SORT_COLLATION} is present
+     * in query args bundle.
      *
-     * TODO: Should we explicitly validate that colums are present in the projection?
+     * TODO: Would be nice to explicitly validate that colums referenced in
+     * {@link #QUERY_ARG_SORT_COLUMNS} are present in the associated projection.
      *
      * @hide
      */
@@ -2934,6 +2994,14 @@
 
         String query = TextUtils.join(", ", columns);
 
+        // Interpret PRIMARY and SECONDARY collation strength as no-case collation based
+        // on their javadoc descriptions.
+        int collation = queryArgs.getInt(
+                ContentResolver.QUERY_ARG_SORT_COLLATION, java.text.Collator.IDENTICAL);
+        if (collation == java.text.Collator.PRIMARY || collation == java.text.Collator.SECONDARY) {
+            query += " COLLATE NOCASE";
+        }
+
         switch (queryArgs.getInt(
                 QUERY_ARG_SORT_DIRECTION, Integer.MIN_VALUE)) {
             case QUERY_SORT_DIRECTION_ASCENDING:
@@ -2946,13 +3014,6 @@
                 throw new IllegalArgumentException("Unsupported sort direction value."
                         + " See ContentResolver documentation for details.");
         }
-
-        // Interpret PRIMARY collation strength as no-case collation.
-        int collation = queryArgs.getInt(
-                ContentResolver.QUERY_ARG_SORT_COLLATION, java.text.Collator.IDENTICAL);
-        if (collation == java.text.Collator.PRIMARY || collation == java.text.Collator.SECONDARY) {
-            query += " COLLATE NOCASE";
-        }
         return query;
     }
 }
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 4b6076b..e437de0 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -653,6 +653,13 @@
         return mBase.bindServiceAsUser(service, conn, flags, user);
     }
 
+    /** @hide */
+    @Override
+    public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+            Handler handler, UserHandle user) {
+        return mBase.bindServiceAsUser(service, conn, flags, handler, user);
+    }
+
     @Override
     public void unbindService(ServiceConnection conn) {
         mBase.unbindService(conn);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d8358f9..8cc9a3a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -715,11 +715,13 @@
     /**
      * Activity Action: Creates a shortcut.
      * <p>Input: Nothing.</p>
-     * <p>Output: An Intent representing the shortcut. The intent must contain three
+     * <p>Output: An Intent representing the {@link android.content.pm.ShortcutInfo} result.</p>
+     * <p>For compatibility with older versions of android the intent may also contain three
      * extras: SHORTCUT_INTENT (value: Intent), SHORTCUT_NAME (value: String),
      * and SHORTCUT_ICON (value: Bitmap) or SHORTCUT_ICON_RESOURCE
      * (value: ShortcutIconResource).</p>
      *
+     * @see android.content.pm.ShortcutManager#createShortcutResultIntent
      * @see #EXTRA_SHORTCUT_INTENT
      * @see #EXTRA_SHORTCUT_NAME
      * @see #EXTRA_SHORTCUT_ICON
@@ -733,26 +735,34 @@
      * The name of the extra used to define the Intent of a shortcut.
      *
      * @see #ACTION_CREATE_SHORTCUT
+     * @deprecated Replaced with {@link android.content.pm.ShortcutManager#createShortcutResultIntent}
      */
+    @Deprecated
     public static final String EXTRA_SHORTCUT_INTENT = "android.intent.extra.shortcut.INTENT";
     /**
      * The name of the extra used to define the name of a shortcut.
      *
      * @see #ACTION_CREATE_SHORTCUT
+     * @deprecated Replaced with {@link android.content.pm.ShortcutManager#createShortcutResultIntent}
      */
+    @Deprecated
     public static final String EXTRA_SHORTCUT_NAME = "android.intent.extra.shortcut.NAME";
     /**
      * The name of the extra used to define the icon, as a Bitmap, of a shortcut.
      *
      * @see #ACTION_CREATE_SHORTCUT
+     * @deprecated Replaced with {@link android.content.pm.ShortcutManager#createShortcutResultIntent}
      */
+    @Deprecated
     public static final String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
     /**
      * The name of the extra used to define the icon, as a ShortcutIconResource, of a shortcut.
      *
      * @see #ACTION_CREATE_SHORTCUT
      * @see android.content.Intent.ShortcutIconResource
+     * @deprecated Replaced with {@link android.content.pm.ShortcutManager#createShortcutResultIntent}
      */
+    @Deprecated
     public static final String EXTRA_SHORTCUT_ICON_RESOURCE =
             "android.intent.extra.shortcut.ICON_RESOURCE";
 
diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl
index 430c7e7..5152416 100644
--- a/core/java/android/content/pm/ILauncherApps.aidl
+++ b/core/java/android/content/pm/ILauncherApps.aidl
@@ -18,6 +18,7 @@
 
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IOnAppsChangedListener;
@@ -60,4 +61,8 @@
             int userId);
 
     boolean hasShortcutHostPermission(String callingPackage);
+
+    ParceledListSlice getShortcutConfigActivities(String packageName, in UserHandle user);
+    IntentSender getShortcutConfigActivityIntent(String callingPackage, in ComponentName component,
+            in UserHandle user);
 }
diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl
index 91df8e8..c90134a 100644
--- a/core/java/android/content/pm/IShortcutService.aidl
+++ b/core/java/android/content/pm/IShortcutService.aidl
@@ -15,6 +15,7 @@
  */
 package android.content.pm;
 
+import android.content.Intent;
 import android.content.IntentSender;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.ShortcutInfo;
@@ -45,6 +46,8 @@
     boolean requestPinShortcut(String packageName, in ShortcutInfo shortcut,
             in IntentSender resultIntent, int userId);
 
+    Intent createShortcutResultIntent(String packageName, in ShortcutInfo shortcut, int userId);
+
     void disableShortcuts(String packageName, in List shortcutIds, CharSequence disabledMessage,
             int disabledMessageResId, int userId);
 
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index 4cdd653..cf873b0 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -27,6 +27,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
@@ -384,25 +385,11 @@
      * @return List of launchable activities. Can be an empty list but will not be null.
      */
     public List<LauncherActivityInfo> getActivityList(String packageName, UserHandle user) {
-        ParceledListSlice<ResolveInfo> activities = null;
         try {
-            activities = mService.getLauncherActivities(packageName, user);
+            return convertToActivityList(mService.getLauncherActivities(packageName, user), user);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
-        if (activities == null) {
-            return Collections.EMPTY_LIST;
-        }
-        ArrayList<LauncherActivityInfo> lais = new ArrayList<LauncherActivityInfo>();
-        for (ResolveInfo ri : activities.getList()) {
-            LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
-            if (DEBUG) {
-                Log.v(TAG, "Returning activity for profile " + user + " : "
-                        + lai.getComponentName());
-            }
-            lais.add(lai);
-        }
-        return lais;
     }
 
     /**
@@ -465,6 +452,73 @@
     }
 
     /**
+     * Retrieves a list of config activities for creating {@link ShortcutInfo}.
+     *
+     * @param packageName The specific package to query. If null, it checks all installed packages
+     *            in the profile.
+     * @param user The UserHandle of the profile.
+     * @return List of config activities. Can be an empty list but will not be null.
+     *
+     * @see Intent#ACTION_CREATE_SHORTCUT
+     * @see #getShortcutConfigActivityIntent(LauncherActivityInfo)
+     */
+    public List<LauncherActivityInfo> getShortcutConfigActivityList(@Nullable String packageName,
+            @NonNull UserHandle user) {
+        try {
+            return convertToActivityList(mService.getShortcutConfigActivities(packageName, user),
+                    user);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    private List<LauncherActivityInfo> convertToActivityList(
+            @Nullable ParceledListSlice<ResolveInfo> activities, UserHandle user) {
+        if (activities == null) {
+            return Collections.EMPTY_LIST;
+        }
+        ArrayList<LauncherActivityInfo> lais = new ArrayList<>();
+        for (ResolveInfo ri : activities.getList()) {
+            LauncherActivityInfo lai = new LauncherActivityInfo(mContext, ri.activityInfo, user);
+            if (DEBUG) {
+                Log.v(TAG, "Returning activity for profile " + user + " : "
+                        + lai.getComponentName());
+            }
+            lais.add(lai);
+        }
+        return lais;
+    }
+
+    /**
+     * Returns an intent sender which can be used to start the configure activity for creating
+     * custom shortcuts. Use this method if the provider is in another profile as you are not
+     * allowed to start an activity in another profile.
+     *
+     * <p>The caller should receive {@link PinItemRequest} in onActivityResult on
+     * {@link android.app.Activity#RESULT_OK}.
+     *
+     * <p>Callers must be allowed to access the shortcut information, as defined in {@link
+     * #hasShortcutHostPermission()}.
+     *
+     * @param info a configuration activity returned by {@link #getShortcutConfigActivityList}
+     *
+     * @throws IllegalStateException when the user is locked or not running.
+     * @throws SecurityException if {@link #hasShortcutHostPermission()} is false.
+     *
+     * @see #getPinItemRequest(Intent)
+     * @see Intent#ACTION_CREATE_SHORTCUT
+     * @see android.app.Activity#startIntentSenderForResult
+     */
+    public IntentSender getShortcutConfigActivityIntent(@NonNull LauncherActivityInfo info) {
+        try {
+            return mService.getShortcutConfigActivityIntent(
+                    mContext.getPackageName(), info.getComponentName(), info.getUser());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Checks if the package is installed and enabled for a profile.
      *
      * @param packageName The package to check.
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index 3853400..805054f 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -881,6 +881,31 @@
     }
 
     /**
+     * Returns an Intent which can be used by the default launcher to pin {@param shortcut}.
+     * This should be used by an Activity to set result in response to
+     * {@link Intent#ACTION_CREATE_SHORTCUT}.
+     *
+     * @param shortcut New shortcut to pin.  If an app wants to pin an existing (either dynamic
+     *     or manifest) shortcut, then it only needs to have an ID, and other fields don't have to
+     *     be set, in which case, the target shortcut must be enabled.
+     *     If it's a new shortcut, all the mandatory fields, such as a short label, must be
+     *     set.
+     * @return The intent that should be set as the result for the calling activity or null.
+     *
+     * @see Intent#ACTION_CREATE_SHORTCUT
+     *
+     * @throws IllegalArgumentException if a shortcut with the same ID exists and is disabled.
+     */
+    public Intent createShortcutResultIntent(@NonNull ShortcutInfo shortcut) {
+        try {
+            return mService.createShortcutResultIntent(mContext.getPackageName(), shortcut,
+                    injectMyUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Called internally when an app is considered to have come to the foreground
      * even when technically it's not.  This method resets the throttling for this package.
      * For example, when the user sends an "inline reply" on a notification, the system UI will
diff --git a/core/java/android/content/res/Configuration.java b/core/java/android/content/res/Configuration.java
index d44af7f..48860f7 100644
--- a/core/java/android/content/res/Configuration.java
+++ b/core/java/android/content/res/Configuration.java
@@ -766,6 +766,11 @@
         }
     }
 
+    /**
+     * Sets the fields in this object to those in the given Configuration.
+     *
+     * @param o The Configuration object used to set the values of this Configuration's fields.
+     */
     public void setTo(Configuration o) {
         fontScale = o.fontScale;
         mcc = o.mcc;
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 04ee1e6..3ccac69 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -492,7 +492,7 @@
         if (type == Sensor.TYPE_PROXIMITY || type == Sensor.TYPE_SIGNIFICANT_MOTION ||
                 type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE ||
                 type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE ||
-                type == Sensor.TYPE_WRIST_TILT_GESTURE) {
+                type == Sensor.TYPE_WRIST_TILT_GESTURE || type == Sensor.TYPE_DYNAMIC_SENSOR_META) {
             wakeUpSensor = true;
         }
 
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 5e9fd66..4befb29 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -48,8 +48,6 @@
 
     /** Input surface configured by native camera framework based on user-specified configuration */
     private final Surface mInput;
-    /** User-specified set of surfaces used as the configuration outputs */
-    private final List<Surface> mOutputs;
     /**
      * User-specified state callback, used for outgoing events; calls to this object will be
      * automatically {@link Handler#post(Runnable) posted} to {@code mStateHandler}.
@@ -87,21 +85,17 @@
      * There must be no pending actions
      * (e.g. no pending captures, no repeating requests, no flush).</p>
      */
-    CameraCaptureSessionImpl(int id, Surface input, List<Surface> outputs,
+    CameraCaptureSessionImpl(int id, Surface input,
             CameraCaptureSession.StateCallback callback, Handler stateHandler,
             android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
             Handler deviceStateHandler, boolean configureSuccess) {
-        if (outputs == null || outputs.isEmpty()) {
-            throw new IllegalArgumentException("outputs must be a non-null, non-empty list");
-        } else if (callback == null) {
+        if (callback == null) {
             throw new IllegalArgumentException("callback must not be null");
         }
 
         mId = id;
         mIdString = String.format("Session %d: ", mId);
 
-        // TODO: extra verification of outputs
-        mOutputs = outputs;
         mInput = input;
         mStateHandler = checkHandler(stateHandler);
         mStateCallback = createUserStateCallbackProxy(mStateHandler, callback);
diff --git a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
index 4481a74..01e58f4 100644
--- a/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraConstrainedHighSpeedCaptureSessionImpl.java
@@ -58,14 +58,14 @@
      * There must be no pending actions
      * (e.g. no pending captures, no repeating requests, no flush).</p>
      */
-    CameraConstrainedHighSpeedCaptureSessionImpl(int id, List<Surface> outputs,
+    CameraConstrainedHighSpeedCaptureSessionImpl(int id,
             CameraCaptureSession.StateCallback callback, Handler stateHandler,
             android.hardware.camera2.impl.CameraDeviceImpl deviceImpl,
             Handler deviceStateHandler, boolean configureSuccess,
             CameraCharacteristics characteristics) {
         mCharacteristics = characteristics;
         CameraCaptureSession.StateCallback wrapperCallback = new WrapperCallback(callback);
-        mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, outputs, wrapperCallback,
+        mSessionImpl = new CameraCaptureSessionImpl(id, /*input*/null, wrapperCallback,
                 stateHandler, deviceImpl, deviceStateHandler, configureSuccess);
     }
 
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index 97ca56ef..d2aeaea 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -501,7 +501,7 @@
             CameraCaptureSession.StateCallback callback, Handler handler)
             throws CameraAccessException {
         if (DEBUG) {
-            Log.d(TAG, "createCaptureSessionByOutputConfiguration");
+            Log.d(TAG, "createCaptureSessionByOutputConfigurations");
         }
 
         // OutputConfiguration objects are immutable, but need to have our own array
@@ -621,19 +621,15 @@
                 }
             }
 
-            List<Surface> outSurfaces = new ArrayList<>(outputConfigurations.size());
-            for (OutputConfiguration config : outputConfigurations) {
-                outSurfaces.add(config.getSurface());
-            }
             // Fire onConfigured if configureOutputs succeeded, fire onConfigureFailed otherwise.
             CameraCaptureSessionCore newSession = null;
             if (isConstrainedHighSpeed) {
                 newSession = new CameraConstrainedHighSpeedCaptureSessionImpl(mNextSessionId++,
-                        outSurfaces, callback, handler, this, mDeviceHandler, configureSuccess,
+                        callback, handler, this, mDeviceHandler, configureSuccess,
                         mCharacteristics);
             } else {
                 newSession = new CameraCaptureSessionImpl(mNextSessionId++, input,
-                        outSurfaces, callback, handler, this, mDeviceHandler,
+                        callback, handler, this, mDeviceHandler,
                         configureSuccess);
             }
 
@@ -1946,24 +1942,33 @@
 
             Runnable failureDispatch = null;
             if (errorCode == ERROR_CAMERA_BUFFER) {
-                final Surface outputSurface =
-                        mConfiguredOutputs.get(resultExtras.getErrorStreamId()).getSurface();
-                if (DEBUG) {
-                    Log.v(TAG, String.format("Lost output buffer reported for frame %d, target %s",
-                            frameNumber, outputSurface));
-                }
-                failureDispatch = new Runnable() {
-                    @Override
-                    public void run() {
-                        if (!CameraDeviceImpl.this.isClosed()){
-                            holder.getCallback().onCaptureBufferLost(
-                                CameraDeviceImpl.this,
-                                request,
-                                outputSurface,
-                                frameNumber);
-                        }
+                // Because 1 stream id could map to multiple surfaces, we need to specify both
+                // streamId and surfaceId.
+                List<Surface> surfaces =
+                        mConfiguredOutputs.get(resultExtras.getErrorStreamId()).getSurfaces();
+                for (Surface surface : surfaces) {
+                    if (!request.containsTarget(surface)) {
+                        continue;
                     }
-                };
+                    if (DEBUG) {
+                        Log.v(TAG, String.format("Lost output buffer reported for frame %d, target %s",
+                                frameNumber, surface));
+                    }
+                    failureDispatch = new Runnable() {
+                        @Override
+                        public void run() {
+                            if (!CameraDeviceImpl.this.isClosed()){
+                                holder.getCallback().onCaptureBufferLost(
+                                    CameraDeviceImpl.this,
+                                    request,
+                                    surface,
+                                    frameNumber);
+                            }
+                        }
+                    };
+                    // Dispatch the failure callback
+                    holder.getHandler().post(failureDispatch);
+                }
             } else {
                 boolean mayHaveBuffers = (errorCode == ERROR_CAMERA_RESULT);
 
@@ -2000,10 +2005,11 @@
                 }
                 mFrameNumberTracker.updateTracker(frameNumber, /*error*/true, request.isReprocess());
                 checkAndFireSequenceComplete();
+
+                // Dispatch the failure callback
+                holder.getHandler().post(failureDispatch);
             }
 
-            // Dispatch the failure callback
-            holder.getHandler().post(failureDispatch);
         }
 
     } // public class CameraDeviceCallbacks
diff --git a/core/java/android/hardware/camera2/params/OutputConfiguration.java b/core/java/android/hardware/camera2/params/OutputConfiguration.java
index f897d85..4654fc2 100644
--- a/core/java/android/hardware/camera2/params/OutputConfiguration.java
+++ b/core/java/android/hardware/camera2/params/OutputConfiguration.java
@@ -31,13 +31,17 @@
 import android.util.Size;
 import android.view.Surface;
 
+import java.util.Arrays;
+import java.util.List;
+import java.util.Collections;
+
 import static com.android.internal.util.Preconditions.*;
 
 /**
  * A class for describing camera output, which contains a {@link Surface} and its specific
  * configuration for creating capture session.
  *
- * @see CameraDevice#createCaptureSessionByOutputConfiguration
+ * @see CameraDevice#createCaptureSessionByOutputConfigurations
  *
  */
 public final class OutputConfiguration implements Parcelable {
@@ -147,6 +151,50 @@
     }
 
     /**
+     * Create a new {@link OutputConfiguration} instance with two surfaces sharing the same stream,
+     * with a surface group ID.
+     *
+     * <p>For advanced use cases, a camera application may require more streams than the combination
+     * guaranteed by {@link CameraDevice#createCaptureSession}. In this case, two compatible
+     * surfaces can be attached to one OutputConfiguration so that they map to one camera stream,
+     * and buffers are reference counted when being consumed by both surfaces. </p>
+     *
+     * <p>Two surfaces are compatible in below 2 cases:</p>
+     *
+     * <ol>
+     * <li> Surfaces with the same size, format, dataSpace, and Surface source class. In this case,
+     * {@link CameraDevice#createCaptureSessionByOutputConfigurations} is guaranteed to succeed.
+     *
+     * <li> Surfaces with the same size, format, and dataSpace, but different Surface
+     * source classes. However, on some devices, the underlying camera device is able to use the
+     * same buffer layout for both surfaces. The only way to discover if this is the case is to
+     * create a capture session with that output configuration. For example, if the camera device
+     * uses the same private buffer format between a SurfaceView/SurfaceTexture and a
+     * MediaRecorder/MediaCodec, {@link CameraDevice#createCaptureSessionByOutputConfigurations}
+     * will succeed. Otherwise, it throws {@code IllegalArgumentException}.
+     * </ol>
+     *
+     * @param surfaceGroupId
+     *          A group ID for this output, used for sharing memory between multiple outputs.
+     * @param surface
+     *          A Surface for camera to output to.
+     * @param surface2
+     *          Second surface for camera to output to.
+     * @throws IllegalArgumentException if the two surfaces have different size, format, or
+     * dataSpace.
+     *
+     * @hide
+     */
+    public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface,
+            @NonNull Surface surface2) {
+        this(surfaceGroupId, surface, ROTATION_0, surface2);
+
+        checkNotNull(surface2, "Surface must not be null");
+        checkMatchingSurfaces(mConfiguredSize, mConfiguredFormat, mConfiguredDataspace,
+                mConfiguredGenerationId, surface2);
+    }
+
+    /**
      * Create a new {@link OutputConfiguration} instance.
      *
      * <p>This constructor takes an argument for desired camera rotation</p>
@@ -169,7 +217,6 @@
         this(SURFACE_GROUP_ID_NONE, surface, rotation);
     }
 
-
     /**
      * Create a new {@link OutputConfiguration} instance, with rotation and a group ID.
      *
@@ -193,17 +240,68 @@
      */
     @SystemApi
     public OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation) {
+        this(surfaceGroupId, surface, rotation, null /*surface2*/);
+    }
+
+    /**
+     * Create a new {@link OutputConfiguration} instance, with rotation, a group ID, and a secondary
+     * surface.
+     *
+     * <p>This constructor takes an argument for desired camera rotation, the surface group
+     * ID, and a secondary surface.  See {@link #OutputConfiguration(int, Surface)} for details
+     * of the group ID.</p>
+     *
+     * <p>surface2 should be compatible with surface. See {@link #OutputConfiguration(int, Surface,
+     * Surface} for details of compatibility between surfaces.</p>
+     *
+     * <p>Since the rotation is done by the CameraDevice, both surfaces will receive buffers with
+     * the same rotation applied. This means that if the application needs two compatible surfaces
+     * to have different rotations, these surfaces cannot be shared within one OutputConfiguration.
+     * </p>
+     *
+     * @param surfaceGroupId
+     *          A group ID for this output, used for sharing memory between multiple outputs.
+     * @param surface
+     *          A Surface for camera to output to.
+     * @param rotation
+     *          The desired rotation to be applied on camera output. Value must be one of
+     *          ROTATION_[0, 90, 180, 270]. Note that when the rotation is 90 or 270 degrees,
+     *          application should make sure corresponding surface size has width and height
+     *          transposed relative to the width and height without rotation. For example,
+     *          if application needs camera to capture 1280x720 picture and rotate it by 90 degree,
+     *          application should set rotation to {@code ROTATION_90} and make sure the
+     *          corresponding Surface size is 720x1280. Note that {@link CameraDevice} might
+     *          throw {@code IllegalArgumentException} if device cannot perform such rotation.
+     * @param surface2
+     *          Second surface for camera to output to.
+
+     * @throws IllegalArgumentException if the two surfaces are not compatible to be shared in
+     *                                  one OutputConfiguration.
+     *
+     * @hide
+     */
+    private OutputConfiguration(int surfaceGroupId, @NonNull Surface surface, int rotation,
+            @Nullable Surface surface2) {
         checkNotNull(surface, "Surface must not be null");
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
+
         mSurfaceGroupId = surfaceGroupId;
         mSurfaceType = SURFACE_TYPE_UNKNOWN;
-        mSurface = surface;
         mRotation = rotation;
         mConfiguredSize = SurfaceUtils.getSurfaceSize(surface);
         mConfiguredFormat = SurfaceUtils.getSurfaceFormat(surface);
         mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(surface);
         mConfiguredGenerationId = surface.getGenerationId();
         mIsDeferredConfig = false;
+
+        if (surface2 == null) {
+            mSurfaces = new Surface[1];
+            mSurfaces[0] = surface;
+        } else {
+            mSurfaces = new Surface[MAX_SURFACES_COUNT];
+            mSurfaces[0] = surface;
+            mSurfaces[1] = surface2;
+        }
     }
 
     /**
@@ -231,25 +329,34 @@
      *            {@link android.graphics.SurfaceTexture SurfaceTexture.class} are supported.
      */
     public <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass) {
-        checkNotNull(klass, "surfaceSize must not be null");
-        checkNotNull(klass, "klass must not be null");
-        if (klass == android.view.SurfaceHolder.class) {
-            mSurfaceType = SURFACE_TYPE_SURFACE_VIEW;
-        } else if (klass == android.graphics.SurfaceTexture.class) {
-            mSurfaceType = SURFACE_TYPE_SURFACE_TEXTURE;
-        } else {
-            mSurfaceType = SURFACE_TYPE_UNKNOWN;
-            throw new IllegalArgumentException("Unknow surface source class type");
-        }
+        this(surfaceSize, klass, true /* dummy */);
 
-        mSurfaceGroupId = SURFACE_GROUP_ID_NONE;
-        mSurface = null;
-        mRotation = ROTATION_0;
-        mConfiguredSize = surfaceSize;
-        mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
-        mConfiguredDataspace = StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
-        mConfiguredGenerationId = 0;
-        mIsDeferredConfig = true;
+        mSurfaces = new Surface[1];
+    }
+
+    /**
+     * Create a new {@link OutputConfiguration} instance, with desired Surface size and Surface
+     * source class for the deferred surface, and a secondary surface.
+     *
+     * <p>This constructor takes an argument for desired surface size and surface source class of
+     * the deferred surface, and a secondary surface. See {@link #OutputConfiguration(Size, Class)}
+     * for details of the surface size and surface source class.</p>
+     *
+     * <p> The deferred surface and secondary surface should be compatible. See
+     * {@link #OutputConfiguration(int, Surface, Surface)} for details of compatible surfaces.
+     *
+     * @hide
+     */
+    public <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass,
+            @NonNull Surface surface2) {
+        this(surfaceSize, klass, true /* dummy */);
+
+        checkMatchingSurfaces(mConfiguredSize, mConfiguredFormat, mConfiguredDataspace,
+                mConfiguredGenerationId, surface2);
+
+        mSurfaces = new Surface[MAX_SURFACES_COUNT];
+        mSurfaces[0] = null;
+        mSurfaces[1] = surface2;
     }
 
     /**
@@ -285,7 +392,7 @@
      */
     public void setDeferredSurface(@NonNull Surface surface) {
         checkNotNull(surface, "Surface must not be null");
-        if (mSurface != null) {
+        if (mSurfaces[0] != null) {
             throw new IllegalStateException("Deferred surface is already set!");
         }
 
@@ -297,7 +404,7 @@
                     ", the pre-configured size will be used.");
         }
 
-        mSurface = surface;
+        mSurfaces[0] = surface;
     }
 
     /**
@@ -313,7 +420,7 @@
             throw new IllegalArgumentException("OutputConfiguration shouldn't be null");
         }
 
-        this.mSurface = other.mSurface;
+        this.mSurfaces = other.mSurfaces;
         this.mRotation = other.mRotation;
         this.mSurfaceGroupId = other.mSurfaceGroupId;
         this.mSurfaceType = other.mSurfaceType;
@@ -325,6 +432,49 @@
     }
 
     /**
+     * Private constructor to initialize Configuration based on surface size and class
+     */
+    private <T> OutputConfiguration(@NonNull Size surfaceSize, @NonNull Class<T> klass,
+            boolean dummy) {
+        checkNotNull(surfaceSize, "surfaceSize must not be null");
+        checkNotNull(klass, "klass must not be null");
+        if (klass == android.view.SurfaceHolder.class) {
+            mSurfaceType = SURFACE_TYPE_SURFACE_VIEW;
+        } else if (klass == android.graphics.SurfaceTexture.class) {
+            mSurfaceType = SURFACE_TYPE_SURFACE_TEXTURE;
+        } else {
+            mSurfaceType = SURFACE_TYPE_UNKNOWN;
+            throw new IllegalArgumentException("Unknow surface source class type");
+        }
+
+        mSurfaceGroupId = SURFACE_GROUP_ID_NONE;
+        mRotation = ROTATION_0;
+        mConfiguredSize = surfaceSize;
+        mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
+        mConfiguredDataspace = StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
+        mConfiguredGenerationId = 0;
+        mIsDeferredConfig = true;
+    }
+
+    /**
+     * Check if the surface properties match that of the given surface.
+     *
+     * @return true if the properties and the surface match.
+     */
+    private void checkMatchingSurfaces(Size size, int format, int dataSpace, int generationId,
+            @NonNull Surface surface) {
+        if (!size.equals(SurfaceUtils.getSurfaceSize(surface))) {
+            throw new IllegalArgumentException("Secondary surface size doesn't match");
+        }
+        if (dataSpace != SurfaceUtils.getSurfaceDataspace(surface)) {
+            throw new IllegalArgumentException("Secondary surface dataspace doesn't match");
+        }
+        if (format != SurfaceUtils.getSurfaceFormat(surface)) {
+            throw new IllegalArgumentException("Secondary surface format doesn't match");
+        }
+    }
+
+    /**
      * Create an OutputConfiguration from Parcel.
      */
     private OutputConfiguration(@NonNull Parcel source) {
@@ -333,25 +483,52 @@
         int surfaceType = source.readInt();
         int width = source.readInt();
         int height = source.readInt();
-        Surface surface = Surface.CREATOR.createFromParcel(source);
+        int surfaceCnt = source.readInt();
+
+        if (surfaceCnt <= 0) {
+            throw new IllegalArgumentException(
+                    "Surface count in OutputConfiguration must be greater than 0");
+        }
+        if (surfaceCnt > MAX_SURFACES_COUNT) {
+            throw new IllegalArgumentException(
+                    "Surface count in OutputConfiguration must not be more than "
+                    + MAX_SURFACES_COUNT);
+        }
+
+        Surface[] surfaces = new Surface[surfaceCnt];
+        for (int i = 0; i < surfaceCnt; i++) {
+            Surface surface = Surface.CREATOR.createFromParcel(source);
+            surfaces[i] = surface;
+
+            if (surface == null && i > 0) {
+                throw new IllegalArgumentException("Only the first surface can be deferred");
+            }
+        }
+
         checkArgumentInRange(rotation, ROTATION_0, ROTATION_270, "Rotation constant");
+
         mSurfaceGroupId = surfaceSetId;
-        mSurface = surface;
         mRotation = rotation;
-        if (surface != null) {
+        mSurfaces = surfaces;
+        mConfiguredSize = new Size(width, height);
+        // First surface could be null (being deferred). Use last surface to look up surface
+        // characteristics.
+        if (mSurfaces[surfaceCnt-1] != null) {
             mSurfaceType = SURFACE_TYPE_UNKNOWN;
-            mConfiguredSize = SurfaceUtils.getSurfaceSize(mSurface);
-            mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurface);
-            mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurface);
-            mConfiguredGenerationId = mSurface.getGenerationId();
-            mIsDeferredConfig = true;
+            mConfiguredFormat = SurfaceUtils.getSurfaceFormat(mSurfaces[surfaceCnt-1]);
+            mConfiguredDataspace = SurfaceUtils.getSurfaceDataspace(mSurfaces[surfaceCnt-1]);
+            mConfiguredGenerationId = mSurfaces[surfaceCnt-1].getGenerationId();
         } else {
             mSurfaceType = surfaceType;
-            mConfiguredSize = new Size(width, height);
             mConfiguredFormat = StreamConfigurationMap.imageFormatToInternal(ImageFormat.PRIVATE);
-            mConfiguredGenerationId = 0;
             mConfiguredDataspace =
                     StreamConfigurationMap.imageFormatToDataspace(ImageFormat.PRIVATE);
+            mConfiguredGenerationId = 0;
+        }
+
+        if (mSurfaces[0] == null) {
+            mIsDeferredConfig = true;
+        } else {
             mIsDeferredConfig = false;
         }
     }
@@ -359,11 +536,27 @@
     /**
      * Get the {@link Surface} associated with this {@link OutputConfiguration}.
      *
-     * @return the {@link Surface} associated with this {@link OutputConfiguration}.
+     * @return the {@link Surface} associated with this {@link OutputConfiguration}. If more than
+     * one surface is associated with this {@link OutputConfiguration}, return the first one as
+     * specified in the constructor. If there is a deferred surface, null will be returned.
+     */
+    public @Nullable Surface getSurface() {
+        return mSurfaces[0];
+    }
+
+    /**
+     * Get the immutable list of surfaces associated with this {@link OutputConfiguration}.
+     *
+     * @return the list of surfaces associated with this {@link OutputConfiguration} in the order
+     * specified in the constructor. If there is a deferred surface in the {@link
+     * OutputConfiguration}, it is returned as null as first element of the list. The list should
+     * not be modified.
+     *
+     * @hide
      */
     @NonNull
-    public Surface getSurface() {
-        return mSurface;
+    public List<Surface> getSurfaces() {
+        return Collections.unmodifiableList(Arrays.asList(mSurfaces));
     }
 
     /**
@@ -423,8 +616,11 @@
         dest.writeInt(mSurfaceType);
         dest.writeInt(mConfiguredSize.getWidth());
         dest.writeInt(mConfiguredSize.getHeight());
-        if (mSurface != null) {
-            mSurface.writeToParcel(dest, flags);
+        dest.writeInt(mSurfaces.length);
+        for (int i = 0; i < mSurfaces.length; i++) {
+            if (mSurfaces[i] != null) {
+                mSurfaces[i].writeToParcel(dest, flags);
+            }
         }
     }
 
@@ -445,20 +641,26 @@
             return true;
         } else if (obj instanceof OutputConfiguration) {
             final OutputConfiguration other = (OutputConfiguration) obj;
-            boolean iSSurfaceEqual = mSurface == other.mSurface &&
-                    mConfiguredGenerationId == other.mConfiguredGenerationId ;
-            if (mIsDeferredConfig) {
-                Log.i(TAG, "deferred config has the same surface");
-                iSSurfaceEqual = true;
+            if (mRotation != other.mRotation ||
+                    !mConfiguredSize.equals(other.mConfiguredSize) ||
+                    mConfiguredFormat != other.mConfiguredFormat ||
+                    mSurfaceGroupId != other.mSurfaceGroupId ||
+                    mSurfaceType != other.mSurfaceType ||
+                    mIsDeferredConfig != other.mIsDeferredConfig ||
+                    mConfiguredFormat != other.mConfiguredFormat ||
+                    mConfiguredDataspace != other.mConfiguredDataspace ||
+                    mSurfaces.length != other.mSurfaces.length ||
+                    mConfiguredGenerationId != other.mConfiguredGenerationId)
+                return false;
+
+            // If deferred, skip the first surface of mSurfaces when comparing.
+            int minIndex = (mIsDeferredConfig ? 1 : 0);
+            for (int i = minIndex;  i < mSurfaces.length; i++) {
+                if (mSurfaces[i] != other.mSurfaces[i])
+                    return false;
             }
-            return mRotation == other.mRotation &&
-                   iSSurfaceEqual&&
-                   mConfiguredSize.equals(other.mConfiguredSize) &&
-                   mConfiguredFormat == other.mConfiguredFormat &&
-                   mConfiguredDataspace == other.mConfiguredDataspace &&
-                   mSurfaceGroupId == other.mSurfaceGroupId &&
-                   mSurfaceType == other.mSurfaceType &&
-                   mIsDeferredConfig == other.mIsDeferredConfig;
+
+            return true;
         }
         return false;
     }
@@ -469,21 +671,22 @@
     @Override
     public int hashCode() {
         // Need ensure that the hashcode remains unchanged after set a deferred surface. Otherwise
-        // The deferred output configuration will be lost in the camera streammap after the deferred
+        // the deferred output configuration will be lost in the camera streammap after the deferred
         // surface is set.
-        if (mIsDeferredConfig) {
-            return HashCodeHelpers.hashCode(
-                    mRotation, mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace,
-                    mSurfaceGroupId, mSurfaceType);
-        }
+        int minIndex = (mIsDeferredConfig ? 1 : 0);
+        Surface nonDeferredSurfaces[] = Arrays.copyOfRange(mSurfaces,
+                minIndex, mSurfaces.length);
+        int surfaceHash = HashCodeHelpers.hashCodeGeneric(nonDeferredSurfaces);
 
         return HashCodeHelpers.hashCode(
-            mRotation, mSurface.hashCode(), mConfiguredGenerationId,
-            mConfiguredSize.hashCode(), mConfiguredFormat, mConfiguredDataspace, mSurfaceGroupId);
+                mRotation, surfaceHash, mConfiguredGenerationId,
+                mConfiguredSize.hashCode(), mConfiguredFormat,
+                mConfiguredDataspace, mSurfaceGroupId);
     }
 
     private static final String TAG = "OutputConfiguration";
-    private Surface mSurface;
+    private static final int MAX_SURFACES_COUNT = 2;
+    private Surface mSurfaces[];
     private final int mRotation;
     private final int mSurfaceGroupId;
     // Surface source type, this is only used by the deferred surface configuration objects.
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index aa109de..4b57078 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -62,6 +62,7 @@
     private static final int MSG_AUTHENTICATION_FAILED = 103;
     private static final int MSG_ERROR = 104;
     private static final int MSG_REMOVED = 105;
+    private static final int MSG_ENUMERATED = 106;
 
     //
     // Error messages from fingerprint hardware during initilization, enrollment, authentication or
@@ -116,6 +117,10 @@
      * the above categories. Vendors are responsible for providing error strings for these errors.
      * @hide
      */
+    public static final int FINGERPRINT_ERROR_VENDOR = 8;
+    /**
+     * @hide
+     */
     public static final int FINGERPRINT_ERROR_VENDOR_BASE = 1000;
 
     //
@@ -167,6 +172,10 @@
      * the above categories. Vendors are responsible for providing error strings for these errors.
      * @hide
      */
+    public static final int FINGERPRINT_ACQUIRED_VENDOR = 6;
+    /**
+     * @hide
+     */
     public static final int FINGERPRINT_ACQUIRED_VENDOR_BASE = 1000;
 
     private IFingerprintService mService;
@@ -175,6 +184,7 @@
     private AuthenticationCallback mAuthenticationCallback;
     private EnrollmentCallback mEnrollmentCallback;
     private RemovalCallback mRemovalCallback;
+    private EnumerateCallback mEnumerateCallback;
     private CryptoObject mCryptoObject;
     private Fingerprint mRemovalFingerprint;
     private Handler mHandler;
@@ -403,6 +413,29 @@
     };
 
     /**
+     * Callback structure provided to {@link FingerprintManager#enumerate(int). Users of
+     * {@link #FingerprintManager()} may optionally provide an implementation of this to
+     * {@link FingerprintManager#enumerate(int, int, EnumerateCallback)} for listening to
+     * fingerprint template removal events.
+     *
+     * @hide
+     */
+    public static abstract class EnumerateCallback {
+        /**
+         * Called when the given fingerprint can't be removed.
+         * @param errMsgId An associated error message id
+         * @param errString An error message indicating why the fingerprint id can't be removed
+         */
+        public void onEnumerateError(int errMsgId, CharSequence errString) { }
+
+        /**
+         * Called when a given fingerprint is successfully removed.
+         * @param fingerprint the fingerprint template that was removed.
+         */
+        public void onEnumerate(Fingerprint fingerprint) { }
+    };
+
+    /**
      * @hide
      */
     public static abstract class LockoutResetCallback {
@@ -484,7 +517,7 @@
                 // Though this may not be a hardware issue, it will cause apps to give up or try
                 // again later.
                 callback.onAuthenticationError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
-                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
+                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
             }
         }
     }
@@ -534,7 +567,7 @@
                 // Though this may not be a hardware issue, it will cause apps to give up or try
                 // again later.
                 callback.onEnrollmentError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
-                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
+                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
             }
         }
     }
@@ -604,7 +637,29 @@
             Log.w(TAG, "Remote exception in remove: ", e);
             if (callback != null) {
                 callback.onRemovalError(fp, FINGERPRINT_ERROR_HW_UNAVAILABLE,
-                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE));
+                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
+            }
+        }
+    }
+
+    /**
+     * Enumerate all fingerprint templates stored in hardware and/or protected storage.
+     * @param userId the user who this fingerprint belongs to
+     * @param callback an optional callback to verify that fingerprint templates have been
+     * successfully removed. May be null of no callback is required.
+     *
+     * @hide
+     */
+    @RequiresPermission(MANAGE_FINGERPRINT)
+    public void enumerate(int userId, @NonNull EnumerateCallback callback) {
+        if (mService != null) try {
+            mEnumerateCallback = callback;
+            mService.enumerate(mToken, userId, mServiceReceiver);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Remote exception in enumerate: ", e);
+            if (callback != null) {
+                callback.onEnumerateError(FINGERPRINT_ERROR_HW_UNAVAILABLE,
+                        getErrorString(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */));
             }
         }
     }
@@ -800,7 +855,8 @@
                     sendEnrollResult((Fingerprint) msg.obj, msg.arg1 /* remaining */);
                     break;
                 case MSG_ACQUIRED:
-                    sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */);
+                    sendAcquiredResult((Long) msg.obj /* deviceId */, msg.arg1 /* acquire info */,
+                            msg.arg2 /* vendorCode */);
                     break;
                 case MSG_AUTHENTICATION_SUCCEEDED:
                     sendAuthenticatedSucceeded((Fingerprint) msg.obj, msg.arg1 /* userId */);
@@ -809,11 +865,15 @@
                     sendAuthenticatedFailed();
                     break;
                 case MSG_ERROR:
-                    sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */);
+                    sendErrorResult((Long) msg.obj /* deviceId */, msg.arg1 /* errMsgId */,
+                            msg.arg2 /* vendorCode */);
                     break;
                 case MSG_REMOVED:
                     sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
                             msg.arg2 /* groupId */);
+                case MSG_ENUMERATED:
+                    sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
+                            msg.arg2 /* groupId */);
             }
         }
 
@@ -834,14 +894,28 @@
             }
         }
 
-        private void sendErrorResult(long deviceId, int errMsgId) {
+        private void sendEnumeratedResult(long deviceId, int fingerId, int groupId) {
+            if (mEnumerateCallback != null) {
+                mEnumerateCallback.onEnumerate(new Fingerprint(null, groupId, fingerId, deviceId));
+            }
+        }
+
+        private void sendErrorResult(long deviceId, int errMsgId, int vendorCode) {
+            // emulate HAL 2.1 behavior and send real errMsgId
+            final int clientErrMsgId = errMsgId == FINGERPRINT_ERROR_VENDOR
+                    ? (vendorCode + FINGERPRINT_ERROR_VENDOR_BASE) : errMsgId;
             if (mEnrollmentCallback != null) {
-                mEnrollmentCallback.onEnrollmentError(errMsgId, getErrorString(errMsgId));
+                mEnrollmentCallback.onEnrollmentError(clientErrMsgId,
+                        getErrorString(errMsgId, vendorCode));
             } else if (mAuthenticationCallback != null) {
-                mAuthenticationCallback.onAuthenticationError(errMsgId, getErrorString(errMsgId));
+                mAuthenticationCallback.onAuthenticationError(clientErrMsgId,
+                        getErrorString(errMsgId, vendorCode));
             } else if (mRemovalCallback != null) {
-                mRemovalCallback.onRemovalError(mRemovalFingerprint, errMsgId,
-                        getErrorString(errMsgId));
+                mRemovalCallback.onRemovalError(mRemovalFingerprint, clientErrMsgId,
+                        getErrorString(errMsgId, vendorCode));
+            } else if (mEnumerateCallback != null) {
+                mEnumerateCallback.onEnumerateError(clientErrMsgId,
+                        getErrorString(errMsgId, vendorCode));
             }
         }
 
@@ -865,18 +939,21 @@
             }
         }
 
-        private void sendAcquiredResult(long deviceId, int acquireInfo) {
+        private void sendAcquiredResult(long deviceId, int acquireInfo, int vendorCode) {
             if (mAuthenticationCallback != null) {
                 mAuthenticationCallback.onAuthenticationAcquired(acquireInfo);
             }
-            final String msg = getAcquiredString(acquireInfo);
+            final String msg = getAcquiredString(acquireInfo, vendorCode);
             if (msg == null) {
                 return;
             }
+            // emulate HAL 2.1 behavior and send real acquiredInfo
+            final int clientInfo = acquireInfo == FINGERPRINT_ACQUIRED_VENDOR
+                    ? (vendorCode + FINGERPRINT_ACQUIRED_VENDOR_BASE) : acquireInfo;
             if (mEnrollmentCallback != null) {
-                mEnrollmentCallback.onEnrollmentHelp(acquireInfo, msg);
+                mEnrollmentCallback.onEnrollmentHelp(clientInfo, msg);
             } else if (mAuthenticationCallback != null) {
-                mAuthenticationCallback.onAuthenticationHelp(acquireInfo, msg);
+                mAuthenticationCallback.onAuthenticationHelp(clientInfo, msg);
             }
         }
     };
@@ -917,7 +994,7 @@
         }
     }
 
-    private String getErrorString(int errMsg) {
+    private String getErrorString(int errMsg, int vendorCode) {
         switch (errMsg) {
             case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
                 return mContext.getString(
@@ -934,20 +1011,19 @@
                 return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
             case FINGERPRINT_ERROR_LOCKOUT:
                 return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
-            default:
-                if (errMsg >= FINGERPRINT_ERROR_VENDOR_BASE) {
-                    int msgNumber = errMsg - FINGERPRINT_ERROR_VENDOR_BASE;
+            case FINGERPRINT_ERROR_VENDOR: {
                     String[] msgArray = mContext.getResources().getStringArray(
                             com.android.internal.R.array.fingerprint_error_vendor);
-                    if (msgNumber < msgArray.length) {
-                        return msgArray[msgNumber];
+                    if (vendorCode < msgArray.length) {
+                        return msgArray[vendorCode];
                     }
                 }
-                return null;
         }
+        Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
+        return null;
     }
 
-    private String getAcquiredString(int acquireInfo) {
+    private String getAcquiredString(int acquireInfo, int vendorCode) {
         switch (acquireInfo) {
             case FINGERPRINT_ACQUIRED_GOOD:
                 return null;
@@ -966,17 +1042,16 @@
             case FINGERPRINT_ACQUIRED_TOO_FAST:
                 return mContext.getString(
                     com.android.internal.R.string.fingerprint_acquired_too_fast);
-            default:
-                if (acquireInfo >= FINGERPRINT_ACQUIRED_VENDOR_BASE) {
-                    int msgNumber = acquireInfo - FINGERPRINT_ACQUIRED_VENDOR_BASE;
+            case FINGERPRINT_ACQUIRED_VENDOR: {
                     String[] msgArray = mContext.getResources().getStringArray(
                             com.android.internal.R.array.fingerprint_acquired_vendor);
-                    if (msgNumber < msgArray.length) {
-                        return msgArray[msgNumber];
+                    if (vendorCode < msgArray.length) {
+                        return msgArray[vendorCode];
                     }
                 }
-                return null;
         }
+        Slog.w(TAG, "Invalid acquired message: " + acquireInfo + ", " + vendorCode);
+        return null;
     }
 
     private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
@@ -988,8 +1063,8 @@
         }
 
         @Override // binder call
-        public void onAcquired(long deviceId, int acquireInfo) {
-            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0, deviceId).sendToTarget();
+        public void onAcquired(long deviceId, int acquireInfo, int vendorCode) {
+            mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, vendorCode, deviceId).sendToTarget();
         }
 
         @Override // binder call
@@ -1003,14 +1078,21 @@
         }
 
         @Override // binder call
-        public void onError(long deviceId, int error) {
-            mHandler.obtainMessage(MSG_ERROR, error, 0, deviceId).sendToTarget();
+        public void onError(long deviceId, int error, int vendorCode) {
+            mHandler.obtainMessage(MSG_ERROR, error, vendorCode, deviceId).sendToTarget();
         }
 
         @Override // binder call
-        public void onRemoved(long deviceId, int fingerId, int groupId) {
+        public void onRemoved(long deviceId, int fingerId, int groupId, int remaining) {
+            // TODO: propagate remaining
             mHandler.obtainMessage(MSG_REMOVED, fingerId, groupId, deviceId).sendToTarget();
         }
+
+        @Override // binder call
+        public void onEnumerated(long deviceId, int fingerId, int groupId, int remaining) {
+            // TODO: propagate remaining
+            mHandler.obtainMessage(MSG_ENUMERATED, fingerId, groupId, deviceId).sendToTarget();
+        }
     };
 
 }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl b/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl
deleted file mode 100644
index f40f8a3..0000000
--- a/core/java/android/hardware/fingerprint/IFingerprintDaemon.aidl
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 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.hardware.fingerprint;
-
-import android.hardware.fingerprint.IFingerprintDaemonCallback;
-
-/**
- * Communication channel from FingerprintService to FingerprintDaemon (fingerprintd)
- * @hide
- */
-
-interface IFingerprintDaemon {
-    int authenticate(long sessionId, int groupId);
-    int cancelAuthentication();
-    int enroll(in byte [] token, int groupId, int timeout);
-    int cancelEnrollment();
-    long preEnroll();
-    int remove(int fingerId, int groupId);
-    long getAuthenticatorId();
-    int setActiveGroup(int groupId, in byte[] path);
-    long openHal();
-    int closeHal();
-    void init(IFingerprintDaemonCallback callback);
-    int postEnroll();
-    int enumerate();
-    int cancelEnumeration();
-}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl b/core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl
deleted file mode 100644
index bd8ad6e..0000000
--- a/core/java/android/hardware/fingerprint/IFingerprintDaemonCallback.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package android.hardware.fingerprint;
-
-/**
- * Communication channel from the fingerprintd back to FingerprintService.
- * @hide
- */
- interface IFingerprintDaemonCallback {
-    void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
-    void onAcquired(long deviceId, int acquiredInfo);
-    void onAuthenticated(long deviceId, int fingerId, int groupId);
-    void onError(long deviceId, int error);
-    void onRemoved(long deviceId, int fingerId, int groupId);
-    void onEnumerate(long deviceId, in int [] fingerIds, in int [] groupIds);
-}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index a83397a..ae3fc37 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -79,4 +79,7 @@
 
     // Explicitly set the active user (for enrolling work profile)
     void setActiveUser(int uid);
+
+    // Enumerate all fingerprints
+    void enumerate(IBinder token, int userId, IFingerprintServiceReceiver receiver);
 }
diff --git a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
index b024b29..370383f 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintServiceReceiver.aidl
@@ -25,9 +25,10 @@
  */
 oneway interface IFingerprintServiceReceiver {
     void onEnrollResult(long deviceId, int fingerId, int groupId, int remaining);
-    void onAcquired(long deviceId, int acquiredInfo);
+    void onAcquired(long deviceId, int acquiredInfo, int vendorCode);
     void onAuthenticationSucceeded(long deviceId, in Fingerprint fp, int userId);
     void onAuthenticationFailed(long deviceId);
-    void onError(long deviceId, int error);
-    void onRemoved(long deviceId, int fingerId, int groupId);
+    void onError(long deviceId, int error, int vendorCode);
+    void onRemoved(long deviceId, int fingerId, int groupId, int remaining);
+    void onEnumerated(long deviceId, int fingerId, int groupId, int remaining);
 }
diff --git a/core/java/android/net/INetworkScoreService.aidl b/core/java/android/net/INetworkScoreService.aidl
index 9573953..82432c7 100644
--- a/core/java/android/net/INetworkScoreService.aidl
+++ b/core/java/android/net/INetworkScoreService.aidl
@@ -21,6 +21,7 @@
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
+import android.os.RemoteCallback;
 
 /**
  * A service for updating network scores from a network scorer application.
@@ -117,4 +118,16 @@
      *         scorer.
      */
     String getActiveScorerPackage();
+    
+    /**
+     * Request a recommendation for the best network to connect to
+     * taking into account the inputs from the {@link RecommendationRequest}.
+     *
+     * @param request a {@link RecommendationRequest} instance containing the details of the request
+     * @param remoteCallback a {@link RemoteCallback} instance to invoke when the recommendation
+     *                       is available.
+     * @throws SecurityException if the caller is not the system
+     */
+    oneway void requestRecommendationAsync(in RecommendationRequest request,
+                                           in RemoteCallback remoteCallback);
 }
diff --git a/core/java/android/net/NetworkIdentity.java b/core/java/android/net/NetworkIdentity.java
index c704ef0..0775bda 100644
--- a/core/java/android/net/NetworkIdentity.java
+++ b/core/java/android/net/NetworkIdentity.java
@@ -24,8 +24,10 @@
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
 import android.os.Build;
+import android.service.NetworkIdentityProto;
 import android.telephony.TelephonyManager;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import java.util.Objects;
 
@@ -110,6 +112,23 @@
         return builder.append("}").toString();
     }
 
+    public void writeToProto(ProtoOutputStream proto, long tag) {
+        final long start = proto.start(tag);
+
+        proto.write(NetworkIdentityProto.TYPE, mType);
+
+        // Not dumping mSubType, subtypes are no longer supported.
+
+        if (mSubscriberId != null) {
+            proto.write(NetworkIdentityProto.SUBSCRIBER_ID, scrubSubscriberId(mSubscriberId));
+        }
+        proto.write(NetworkIdentityProto.NETWORK_ID, mNetworkId);
+        proto.write(NetworkIdentityProto.ROAMING, mRoaming);
+        proto.write(NetworkIdentityProto.METERED, mMetered);
+
+        proto.end(start);
+    }
+
     public int getType() {
         return mType;
     }
diff --git a/core/java/android/net/NetworkScoreManager.java b/core/java/android/net/NetworkScoreManager.java
index 2870dd6..57cf1a5 100644
--- a/core/java/android/net/NetworkScoreManager.java
+++ b/core/java/android/net/NetworkScoreManager.java
@@ -16,18 +16,28 @@
 
 package android.net;
 
+import static android.net.NetworkRecommendationProvider.EXTRA_RECOMMENDATION_RESULT;
+
+import android.Manifest;
 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.net.NetworkScorerAppManager.NetworkScorerAppData;
+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.concurrent.CompletableFuture;
 
 /**
  * Class that manages communication between network subsystems and a network scorer.
@@ -354,4 +364,43 @@
             throw e.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * Request a recommendation for which network to connect to.
+     *
+     * <p>The callback will be run on the thread associated with provided {@link Handler}.
+     *
+     * @param request a {@link RecommendationRequest} instance containing additional
+     *                request details
+     * @param handler a {@link Handler} instance representing the thread to complete the future on.
+     *                If null the responding binder thread will be used.
+     * @return a {@link CompletableFuture} instance that will eventually receive the
+     *         {@link RecommendationResult}.
+     * @throws SecurityException
+     * @hide
+     */
+    public CompletableFuture<RecommendationResult> requestRecommendation(
+            final @NonNull RecommendationRequest request,
+            final @Nullable Handler handler) {
+        Preconditions.checkNotNull(request, "RecommendationRequest cannot be null.");
+
+        final CompletableFuture<RecommendationResult> futureResult =
+                new CompletableFuture<>();
+
+        RemoteCallback remoteCallback = new RemoteCallback(new RemoteCallback.OnResultListener() {
+            @Override
+            public void onResult(Bundle data) {
+                RecommendationResult result = data.getParcelable(EXTRA_RECOMMENDATION_RESULT);
+                futureResult.complete(result);
+            }
+        }, handler);
+
+        try {
+            mService.requestRecommendationAsync(request, remoteCallback);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+
+        return futureResult;
+    }
 }
diff --git a/core/java/android/net/NetworkStatsHistory.java b/core/java/android/net/NetworkStatsHistory.java
index 4a4accb..5f521de 100644
--- a/core/java/android/net/NetworkStatsHistory.java
+++ b/core/java/android/net/NetworkStatsHistory.java
@@ -31,7 +31,10 @@
 
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.service.NetworkStatsHistoryBucketProto;
+import android.service.NetworkStatsHistoryProto;
 import android.util.MathUtils;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.IndentingPrintWriter;
 
@@ -628,6 +631,33 @@
         }
     }
 
+    public void writeToProto(ProtoOutputStream proto, long tag) {
+        final long start = proto.start(tag);
+
+        proto.write(NetworkStatsHistoryProto.BUCKET_DURATION_MS, bucketDuration);
+
+        for (int i = 0; i < bucketCount; i++) {
+            final long startBucket = proto.start(NetworkStatsHistoryProto.BUCKETS);
+
+            proto.write(NetworkStatsHistoryBucketProto.BUCKET_START_MS, bucketStart[i]);
+            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_BYTES, rxBytes, i);
+            writeToProto(proto, NetworkStatsHistoryBucketProto.RX_PACKETS, rxPackets, i);
+            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_BYTES, txBytes, i);
+            writeToProto(proto, NetworkStatsHistoryBucketProto.TX_PACKETS, txPackets, i);
+            writeToProto(proto, NetworkStatsHistoryBucketProto.OPERATIONS, operations, i);
+
+            proto.end(startBucket);
+        }
+
+        proto.end(start);
+    }
+
+    private static void writeToProto(ProtoOutputStream proto, long tag, long[] array, int index) {
+        if (array != null) {
+            proto.write(tag, array[index]);
+        }
+    }
+
     @Override
     public String toString() {
         final CharArrayWriter writer = new CharArrayWriter();
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index daf8b2d..80ecf97 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -887,6 +887,21 @@
             "eng".equals(getString("ro.build.type"));
 
     /**
+     * Whether this build is running inside a container.
+     *
+     * We should try to avoid checking this flag if possible to minimize
+     * unnecessarily diverging from non-container Android behavior.
+     * Checking this flag is acceptable when low-level resources being
+     * different, e.g. the availability of certain capabilities, access to
+     * system resources being restricted, and the fact that the host OS might
+     * handle some features for us.
+     * For higher-level behavior differences, other checks should be preferred.
+     * @hide
+     */
+    public static final boolean IS_CONTAINER =
+            SystemProperties.getBoolean("ro.boot.container", false);
+
+    /**
      * Specifies whether the permissions needed by a legacy app should be
      * reviewed before any of its components can run. A legacy app is one
      * with targetSdkVersion < 23, i.e apps using the old permission model.
diff --git a/core/java/android/os/IRecoverySystem.aidl b/core/java/android/os/IRecoverySystem.aidl
index 1ee83ae..c5ceecd 100644
--- a/core/java/android/os/IRecoverySystem.aidl
+++ b/core/java/android/os/IRecoverySystem.aidl
@@ -25,5 +25,5 @@
     boolean uncrypt(in String packageFile, IRecoverySystemProgressListener listener);
     boolean setupBcb(in String command);
     boolean clearBcb();
-    void rebootRecoveryWithCommand(in String command, in boolean update);
+    void rebootRecoveryWithCommand(in String command);
 }
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 9513854..1c2588a 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -19,6 +19,7 @@
 
 import android.os.Bundle;
 import android.os.PersistableBundle;
+import android.os.UserManager;
 import android.content.pm.UserInfo;
 import android.content.IntentSender;
 import android.content.RestrictionEntry;
@@ -61,6 +62,7 @@
     int getUserSerialNumber(int userHandle);
     int getUserHandle(int userSerialNumber);
     int getUserRestrictionSource(String restrictionKey, int userHandle);
+    List<UserManager.EnforcingUser> getUserRestrictionSources(String restrictionKey, int userHandle);
     Bundle getUserRestrictions(int userHandle);
     boolean hasBaseUserRestriction(String restrictionKey, int userHandle);
     boolean hasUserRestriction(in String restrictionKey, int userHandle);
diff --git a/core/java/android/os/IProxyFileDescriptorCallback.java b/core/java/android/os/ProxyFileDescriptorCallback.java
similarity index 69%
rename from core/java/android/os/IProxyFileDescriptorCallback.java
rename to core/java/android/os/ProxyFileDescriptorCallback.java
index e41e194..2e9f8d9 100644
--- a/core/java/android/os/IProxyFileDescriptorCallback.java
+++ b/core/java/android/os/ProxyFileDescriptorCallback.java
@@ -17,18 +17,20 @@
 package android.os;
 
 import android.system.ErrnoException;
+import android.system.OsConstants;
 
 /**
  * Callback that handles file system requests from ProxyFileDescriptor.
- * @hide
  */
-public interface IProxyFileDescriptorCallback {
+public abstract class ProxyFileDescriptorCallback {
     /**
      * Returns size of bytes provided by the file descriptor.
      * @return Size of bytes
      * @throws ErrnoException
      */
-    long onGetSize() throws ErrnoException;
+    public long onGetSize() throws ErrnoException {
+        throw new ErrnoException("onGetSize", OsConstants.EBADF);
+    }
 
     /**
      * Provides bytes read from file descriptor.
@@ -39,7 +41,9 @@
      * @return Size of bytes returned by the function.
      * @throws ErrnoException
      */
-    int onRead(long offset, int size, byte[] data) throws ErrnoException;
+    public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+        throw new ErrnoException("onRead", OsConstants.EBADF);
+    }
 
     /**
      * Handles bytes written to file descriptor.
@@ -49,11 +53,20 @@
      * @return Size of bytes processed by the function.
      * @throws ErrnoException
      */
-    int onWrite(long offset, int size, byte[] data) throws ErrnoException;
+    public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
+        throw new ErrnoException("onWrite", OsConstants.EBADF);
+    }
 
     /**
      * Processes fsync request.
      * @throws ErrnoException
      */
-    void onFsync() throws ErrnoException;
+    public void onFsync() throws ErrnoException {
+        throw new ErrnoException("onFsync", OsConstants.EINVAL);
+    }
+
+    /**
+     * Invoked after the file is closed.
+     */
+    abstract public void onRelease();
 }
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 7f9ea438..d48431a 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -491,10 +491,15 @@
                 command += securityArg;
             }
 
-            // RECOVERY_SERVICE writes to BCB (bootloader control block) and triggers the reboot.
             RecoverySystem rs = (RecoverySystem) context.getSystemService(
                     Context.RECOVERY_SERVICE);
-            rs.rebootRecoveryWithCommand(command, true /* update */);
+            if (!rs.setupBcb(command)) {
+                throw new IOException("Setup BCB failed");
+            }
+
+            // Having set up the BCB (bootloader control block), go ahead and reboot
+            PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+            pm.reboot(PowerManager.REBOOT_RECOVERY_UPDATE);
 
             throw new IOException("Reboot failed (no permissions?)");
         }
@@ -708,7 +713,7 @@
         // Write the command into BCB (bootloader control block) and boot from
         // there. Will not return unless failed.
         RecoverySystem rs = (RecoverySystem) context.getSystemService(Context.RECOVERY_SERVICE);
-        rs.rebootRecoveryWithCommand(command.toString(), false);
+        rs.rebootRecoveryWithCommand(command.toString());
 
         throw new IOException("Reboot failed (no permissions?)");
     }
@@ -908,9 +913,9 @@
      * Talks to RecoverySystemService via Binder to set up the BCB command and
      * reboot into recovery accordingly.
      */
-    private void rebootRecoveryWithCommand(String command, boolean update) {
+    private void rebootRecoveryWithCommand(String command) {
         try {
-            mService.rebootRecoveryWithCommand(command, update);
+            mService.rebootRecoveryWithCommand(command);
         } catch (RemoteException ignored) {
         }
     }
diff --git a/core/java/android/os/UserManager.aidl b/core/java/android/os/UserManager.aidl
new file mode 100644
index 0000000..2611b0f
--- /dev/null
+++ b/core/java/android/os/UserManager.aidl
@@ -0,0 +1,20 @@
+/*
+**
+** Copyright 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.os;
+
+parcelable UserManager.EnforcingUser;
\ No newline at end of file
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 3478eaa..efacb20 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1187,7 +1187,9 @@
      * @return The source of user restriction. Any combination of {@link #RESTRICTION_NOT_SET},
      *         {@link #RESTRICTION_SOURCE_SYSTEM}, {@link #RESTRICTION_SOURCE_DEVICE_OWNER}
      *         and {@link #RESTRICTION_SOURCE_PROFILE_OWNER}
+     * @deprecated use {@link #getUserRestrictionSources(String, int)} instead.
      */
+    @Deprecated
     @SystemApi
     @UserRestrictionSource
     public int getUserRestrictionSource(String restrictionKey, UserHandle userHandle) {
@@ -1199,6 +1201,25 @@
     }
 
     /**
+     * @hide
+     *
+     * Returns a list of users who set a user restriction on a given user.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     * @param restrictionKey the string key representing the restriction
+     * @param userHandle the UserHandle of the user for whom to retrieve the restrictions.
+     * @return a list of user ids enforcing this restriction.
+     */
+    @SystemApi
+    public List<EnforcingUser> getUserRestrictionSources(
+            String restrictionKey, UserHandle userHandle) {
+        try {
+            return mService.getUserRestrictionSources(restrictionKey, userHandle.getIdentifier());
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Returns the user-wide restrictions imposed on this user.
      * @return a Bundle containing all the restrictions.
      */
@@ -2310,8 +2331,8 @@
      * @hide
      * Checks if any uninitialized user has the specific seed account name and type.
      *
-     * @param mAccountName The account name to check for
-     * @param mAccountType The account type of the account to check for
+     * @param accountName The account name to check for
+     * @param accountType The account type of the account to check for
      * @return whether the seed account was found
      */
     public boolean someUserHasSeedAccount(String accountName, String accountType) {
@@ -2321,4 +2342,73 @@
             throw re.rethrowFromSystemServer();
         }
     }
+
+    /**
+     * @hide
+     * User that enforces a restriction.
+     *
+     * @see #getUserRestrictionSources(String, UserHandle)
+     */
+    @SystemApi
+    public static final class EnforcingUser implements Parcelable {
+        private final @UserIdInt int userId;
+        private final @UserRestrictionSource int userRestrictionSource;
+
+        /**
+         * @hide
+         */
+        public EnforcingUser(
+                @UserIdInt int userId, @UserRestrictionSource int userRestrictionSource) {
+            this.userId = userId;
+            this.userRestrictionSource = userRestrictionSource;
+        }
+
+        private EnforcingUser(Parcel in) {
+            userId = in.readInt();
+            userRestrictionSource = in.readInt();
+        }
+
+        public static final Creator<EnforcingUser> CREATOR = new Creator<EnforcingUser>() {
+            @Override
+            public EnforcingUser createFromParcel(Parcel in) {
+                return new EnforcingUser(in);
+            }
+
+            @Override
+            public EnforcingUser[] newArray(int size) {
+                return new EnforcingUser[size];
+            }
+        };
+
+        @Override
+        public int describeContents() {
+            return 0;
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(userId);
+            dest.writeInt(userRestrictionSource);
+        }
+
+        /**
+         * Returns an id of the enforcing user.
+         *
+         * <p> Will be UserHandle.USER_NULL when restriction is set by the system.
+         */
+        public UserHandle getUserHandle() {
+            return UserHandle.of(userId);
+        }
+
+        /**
+         * Returns the status of the enforcing user.
+         *
+         * <p> One of {@link #RESTRICTION_SOURCE_SYSTEM},
+         * {@link #RESTRICTION_SOURCE_DEVICE_OWNER} and
+         * {@link #RESTRICTION_SOURCE_PROFILE_OWNER}
+         */
+        public @UserRestrictionSource int getUserRestrictionSource() {
+            return userRestrictionSource;
+        }
+    }
 }
diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java
index 466a7e3..97da588 100644
--- a/core/java/android/os/UserManagerInternal.java
+++ b/core/java/android/os/UserManagerInternal.java
@@ -15,7 +15,6 @@
  */
 package android.os;
 
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.pm.UserInfo;
 import android.graphics.Bitmap;
@@ -24,6 +23,10 @@
  * @hide Only for use within the system server.
  */
 public abstract class UserManagerInternal {
+    public static final int CAMERA_NOT_DISABLED = 0;
+    public static final int CAMERA_DISABLED_LOCALLY = 1;
+    public static final int CAMERA_DISABLED_GLOBALLY = 2;
+
     public interface UserRestrictionsListener {
         /**
          * Called when a user restriction changes.
@@ -36,18 +39,19 @@
     }
 
     /**
-     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService}
-     * to set per-user as well as global user restrictions.
+     * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to set
+     * restrictions enforced by the user.
      *
      * @param userId target user id for the local restrictions.
-     * @param localRestrictions per-user restrictions.
-     *     Caller must not change it once passed to this method.
-     * @param globalRestrictions global restrictions set by DO.  Must be null when PO changed user
-     *     restrictions, in which case global restrictions won't change.
-     *     Caller must not change it once passed to this method.
+     * @param restrictions a bundle of user restrictions.
+     * @param isDeviceOwner whether {@code userId} corresponds to device owner user id.
+     * @param cameraRestrictionScope is camera disabled and if so what is the scope of restriction.
+     *        Should be one of {@link #CAMERA_NOT_DISABLED}, {@link #CAMERA_DISABLED_LOCALLY} or
+     *                               {@link #CAMERA_DISABLED_GLOBALLY}
      */
-    public abstract void setDevicePolicyUserRestrictions(int userId,
-            @NonNull Bundle localRestrictions, @Nullable Bundle globalRestrictions);
+    public abstract void setDevicePolicyUserRestrictions(int userId, @Nullable Bundle restrictions,
+            boolean isDeviceOwner, int cameraRestrictionScope);
+
     /**
      * Returns the "base" user restrictions.
      *
diff --git a/core/java/android/os/storage/IStorageManager.aidl b/core/java/android/os/storage/IStorageManager.aidl
index 27c0526..59394b2 100644
--- a/core/java/android/os/storage/IStorageManager.aidl
+++ b/core/java/android/os/storage/IStorageManager.aidl
@@ -25,6 +25,7 @@
 import android.os.storage.StorageVolume;
 import android.os.storage.VolumeInfo;
 import android.os.storage.VolumeRecord;
+import com.android.internal.os.AppFuseMount;
 
 /**
  * WARNING! Update IMountService.h and IMountService.cpp if you change this
@@ -289,4 +290,6 @@
     void addUserKeyAuth(int userId, int serialNumber, in byte[] token, in byte[] secret) = 70;
     void fixateNewestUserKeyAuth(int userId) = 71;
     void fstrim(int flags) = 72;
+    AppFuseMount mountProxyFileDescriptorBridge() = 73;
+    ParcelFileDescriptor openProxyFileDescriptor(int mountPointId, int fileId, int mode) = 74;
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 03fd8d3..85df48f 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -30,6 +30,7 @@
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
+import android.os.ProxyFileDescriptorCallback;
 import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
@@ -44,7 +45,10 @@
 import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseArray;
-
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.os.AppFuseMount;
+import com.android.internal.os.FuseAppLoop;
 import com.android.internal.os.RoSystemProperties;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.util.Preconditions;
@@ -62,6 +66,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Objects;
+import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -1322,6 +1327,90 @@
         }
     }
 
+
+    /** {@hide} */
+    @VisibleForTesting
+    public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
+            int mode, ProxyFileDescriptorCallback callback, ThreadFactory factory)
+                    throws IOException {
+        // Retry is needed because the mount point mFuseAppLoop is using may be unmounted before
+        // invoking StorageManagerService#openProxyFileDescriptor. In this case, we need to re-mount
+        // the bridge by calling mountProxyFileDescriptorBridge.
+        int retry = 3;
+        while (retry-- > 0) {
+            try {
+                synchronized (mFuseAppLoopLock) {
+                    if (mFuseAppLoop == null) {
+                        final AppFuseMount mount = mStorageManager.mountProxyFileDescriptorBridge();
+                        if (mount == null) {
+                            Log.e(TAG, "Failed to open proxy file bridge.");
+                            throw new IOException("Failed to open proxy file bridge.");
+                        }
+                        mFuseAppLoop = FuseAppLoop.open(mount.mountPointId, mount.fd, factory);
+                    }
+
+                    try {
+                        final int fileId = mFuseAppLoop.registerCallback(callback);
+                        final ParcelFileDescriptor pfd =
+                                mStorageManager.openProxyFileDescriptor(
+                                        mFuseAppLoop.getMountPointId(), fileId, mode);
+                        if (pfd != null) {
+                            return pfd;
+                        }
+                        // Probably the bridge is being unmounted but mFuseAppLoop has not been
+                        // noticed it yet.
+                        mFuseAppLoop.unregisterCallback(fileId);
+                    } catch (FuseAppLoop.UnmountedException error) {
+                        Log.d(TAG, "mFuseAppLoop has been already unmounted.");
+                        mFuseAppLoop = null;
+                        continue;
+                    }
+                }
+                try {
+                    Thread.sleep(100);
+                } catch (InterruptedException e) {
+                    break;
+                }
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
+        }
+
+        throw new IOException("Failed to mount bridge.");
+    }
+
+    /**
+     * Opens seekable ParcelFileDescriptor that routes file operation requests to
+     * ProxyFileDescriptorCallback.
+     *
+     * @param mode The desired access mode, must be one of
+     *     {@link ParcelFileDescriptor#MODE_READ_ONLY},
+     *     {@link ParcelFileDescriptor#MODE_WRITE_ONLY}, or
+     *     {@link ParcelFileDescriptor#MODE_READ_WRITE}
+     * @param callback Callback to process file operation requests issued on returned file
+     *     descriptor. The callback is invoked on a thread managed by the framework.
+     * @return Seekable ParcelFileDescriptor.
+     * @throws IOException
+     */
+    public @NonNull ParcelFileDescriptor openProxyFileDescriptor(
+            int mode, ProxyFileDescriptorCallback callback)
+                    throws IOException {
+        return openProxyFileDescriptor(mode, callback, null);
+    }
+
+    /** {@hide} */
+    @VisibleForTesting
+    public int getProxyFileDescriptorMountPointId() {
+        synchronized (mFuseAppLoopLock) {
+            return mFuseAppLoop != null ? mFuseAppLoop.getMountPointId() : -1;
+        }
+    }
+
+    private final Object mFuseAppLoopLock = new Object();
+
+    @GuardedBy("mFuseAppLoopLock")
+    private @Nullable FuseAppLoop mFuseAppLoop = null;
+
     /// Consts to match the password types in cryptfs.h
     /** @hide */
     public static final int CRYPT_TYPE_PASSWORD = 0;
diff --git a/core/java/android/provider/ContactsContract.java b/core/java/android/provider/ContactsContract.java
index a07aee5..1b512c6 100644
--- a/core/java/android/provider/ContactsContract.java
+++ b/core/java/android/provider/ContactsContract.java
@@ -8170,11 +8170,29 @@
         /**
          * The content:// style URI for this table.  Requests to this URI can be
          * performed on the UI thread because they are always unblocking.
+         *
+         * <p>Note when you listen on this URI (or any other sub-URIs), you'll be notified for
+         * regular contact change notifications too, which will be sent on the root URI.
+         * If you only want to be notified for provider status change notifications, listen on
+         * {@link #STATUS_CHANGE_NOTIFICATION_CONTENT_URI} instead.
          */
         public static final Uri CONTENT_URI =
                 Uri.withAppendedPath(AUTHORITY_URI, "provider_status");
 
         /**
+         * URI to listen to provider status changes without listening to regular
+         * contact changes.  If a client only wants to monitor {@link ProviderStatus} with
+         * {@link android.app.job.JobScheduler}, then this URI should be used instead of
+         * {@link #CONTENT_URI}, because a job on {@link #CONTENT_URI} will also be invoked
+         * when contacts are changed.
+         *
+         * <p>Note this URI cannot be queried.  A query should be always made on
+         * {@link #CONTENT_URI}.
+         */
+        public static final Uri STATUS_CHANGE_NOTIFICATION_CONTENT_URI =
+                Uri.parse("content://com.android.contacts.provider_status");
+
+        /**
          * The MIME-type of {@link #CONTENT_URI} providing a directory of
          * settings.
          */
@@ -8201,6 +8219,13 @@
          * on the device.
          */
         public static final int STATUS_EMPTY = 2;
+
+        /**
+         * Timestamp (milliseconds since epoch) of when the provider's database was created.
+         *
+         * <P>Type: long
+         */
+        public static final String DATABASE_CREATION_TIMESTAMP = "database_creation_timestamp";
     }
 
     /**
@@ -8768,7 +8793,14 @@
         /**
          * This is the intent that is fired when the contacts database is created. <p> The
          * READ_CONTACT permission is required to receive these broadcasts.
+         *
+         * <p>As of O, this broadcast will no longer be sent.  Applications can use
+         * use {@link android.app.job.JobScheduler} to monitor
+         * {@link ProviderStatus#STATUS_CHANGE_NOTIFICATION_CONTENT_URI}, and read
+         * {@link ProviderStatus#DATABASE_CREATION_TIMESTAMP} to get when
+         * the contacts database was initialized.
          */
+        @Deprecated
         public static final String CONTACTS_DATABASE_CREATED =
                 "android.provider.Contacts.DATABASE_CREATED";
 
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index ded715f..a6e6fda 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -28,6 +28,7 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ResolveInfo;
 import android.content.res.AssetFileDescriptor;
 import android.database.Cursor;
@@ -422,6 +423,14 @@
         public static final int FLAG_SUPPORTS_SETTINGS = 1 << 11;
 
         /**
+         * Flag indicating that a Web link can be obtained for the document.
+         *
+         * @see #COLUMN_FLAGS
+         * @see DocumentsContract#createWebLinkIntent(PackageManager, Uri, Bundle)
+         */
+        public static final int FLAG_WEB_LINKABLE = 1 << 12;
+
+        /**
          * Flag indicating that a document is not complete, likely its
          * contents are being downloaded. Partial files cannot be opened,
          * copied, moved in the UI. But they can be deleted and retried
@@ -685,12 +694,20 @@
     public static final String METHOD_EJECT_ROOT = "android:ejectRoot";
     /** {@hide} */
     public static final String METHOD_FIND_DOCUMENT_PATH = "android:findDocumentPath";
+    /** {@hide} */
+    public static final String METHOD_CREATE_WEB_LINK_INTENT = "android:createWebLinkIntent";
 
     /** {@hide} */
     public static final String EXTRA_PARENT_URI = "parentUri";
     /** {@hide} */
     public static final String EXTRA_URI = "uri";
 
+    /**
+     * @see #createWebLinkIntent(ContentResolver, Uri, Bundle)
+     * {@hide}
+     */
+    public static final String EXTRA_OPTIONS = "options";
+
     private static final String PATH_ROOT = "root";
     private static final String PATH_RECENT = "recent";
     private static final String PATH_DOCUMENT = "document";
@@ -1401,6 +1418,85 @@
     }
 
     /**
+     * Creates an intent for obtaining a web link for the specified document.
+     *
+     * <p>Note, that due to internal limitations, if there is already a web link
+     * intent created for the specified document but with different options,
+     * then it may be overriden.
+     *
+     * <p>Providers are required to show confirmation UI for all new permissions granted
+     * for the linked document.
+     *
+     * <p>If list of recipients is known, then it should be passed in options as
+     * {@link Intent#EXTRA_EMAIL} as either a string or list of strings. Note, that
+     * this is just a hint for the provider, which can ignore the list. In either
+     * case the provider is required to show a UI for letting the user confirm
+     * any new permission grants.
+     *
+     * <p>Since this API may show a UI, it cannot be called from background.
+     *
+     * <p>In order to obtain the Web Link use code like this:
+     * <pre><code>
+     * void onSomethingHappened() {
+     *   IntentSender sender = DocumentsContract.createWebLinkIntent(<i>...</i>);
+     *   if (sender != null) {
+     *     startIntentSenderForResult(
+     *         DocumentsContract.createWebLinkIntent(<i>...</i>),
+     *         WEB_LINK_REQUEST_CODE,
+     *         null, 0, 0, 0, null);
+     *   }
+     * }
+     *
+     * <i>(...)</i>
+     *
+     * void onActivityResult(int requestCode, int resultCode, Intent data) {
+     *   if (requestCode == WEB_LINK_REQUEST_CODE && resultCode == RESULT_OK) {
+     *     Uri weblinkUri = data.getData();
+     *     <i>...</i>
+     *   }
+     * }
+     * </code></pre>
+     *
+     * @param uri uri for the document to create a link to.
+     * @param options Extra information for generating the link.
+     * @return an intent sender to obtain the web link, or null if the document
+     *      is not linkable, or creating the intent sender failed.
+     * @see DocumentsProvider#createWebLinkIntent(String, Bundle)
+     * @see Intent#EXTRA_EMAIL
+     */
+    public static IntentSender createWebLinkIntent(ContentResolver resolver, Uri uri,
+            Bundle options) {
+        final ContentProviderClient client = resolver.acquireUnstableContentProviderClient(
+                uri.getAuthority());
+        try {
+            return createWebLinkIntent(client, uri, options);
+        } catch (Exception e) {
+            Log.w(TAG, "Failed to create a web link intent", e);
+            return null;
+        } finally {
+            ContentProviderClient.releaseQuietly(client);
+        }
+    }
+
+    /**
+     * {@hide}
+     */
+    public static IntentSender createWebLinkIntent(ContentProviderClient client, Uri uri,
+            Bundle options) throws RemoteException {
+        final Bundle in = new Bundle();
+        in.putParcelable(DocumentsContract.EXTRA_URI, uri);
+
+        // Options may be provider specific, so put them in a separate bundle to
+        // avoid overriding the Uri.
+        if (options != null) {
+            in.putBundle(EXTRA_OPTIONS, options);
+        }
+
+        final Bundle out = client.call(METHOD_CREATE_WEB_LINK_INTENT, null, in);
+        return out.getParcelable(DocumentsContract.EXTRA_RESULT);
+    }
+
+    /**
      * Open the given image for thumbnail purposes, using any embedded EXIF
      * thumbnail if available, and providing orientation hints from the parent
      * image.
diff --git a/core/java/android/provider/DocumentsProvider.java b/core/java/android/provider/DocumentsProvider.java
index 8bc03ee..6170eb4 100644
--- a/core/java/android/provider/DocumentsProvider.java
+++ b/core/java/android/provider/DocumentsProvider.java
@@ -18,6 +18,7 @@
 
 import static android.provider.DocumentsContract.METHOD_COPY_DOCUMENT;
 import static android.provider.DocumentsContract.METHOD_CREATE_DOCUMENT;
+import static android.provider.DocumentsContract.METHOD_CREATE_WEB_LINK_INTENT;
 import static android.provider.DocumentsContract.METHOD_DELETE_DOCUMENT;
 import static android.provider.DocumentsContract.METHOD_EJECT_ROOT;
 import static android.provider.DocumentsContract.METHOD_FIND_DOCUMENT_PATH;
@@ -43,6 +44,7 @@
 import android.content.ContentValues;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.UriMatcher;
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
@@ -363,6 +365,33 @@
     }
 
     /**
+     * Creates an intent sender for a web link, if the document is web linkable.
+     * <p>
+     * Before any new permissions are granted for the linked document, a visible
+     * UI must be shown, so the user can explicitly confirm whether the permission
+     * grants are expected. The user must be able to cancel the operation.
+     * <p>
+     * Options passed as an argument may include a list of recipients, such
+     * as email addresses. The provider should reflect these options if possible,
+     * but it's acceptable to ignore them. In either case, confirmation UI must
+     * be shown before any new permission grants are granted.
+     * <p>
+     * It is all right to generate a web link without granting new permissions,
+     * if opening the link would result in a page for requesting permission
+     * access. If it's impossible then the operation must fail by throwing an exception.
+     *
+     * @param documentId the document to create a web link intent for.
+     * @param options additional information, such as list of recipients. Optional.
+     *
+     * @see DocumentsContract.Document#FLAG_WEB_LINKABLE
+     * @see android.app.PendingIntent#getIntentSender
+     */
+    public IntentSender createWebLinkIntent(String documentId, @Nullable Bundle options)
+            throws FileNotFoundException {
+        throw new UnsupportedOperationException("createWebLink is not supported.");
+    }
+
+    /**
      * Return all roots currently provided. To display to users, you must define
      * at least one root. You should avoid making network requests to keep this
      * request fast.
@@ -900,6 +929,14 @@
                     newDocumentId);
             out.putParcelable(DocumentsContract.EXTRA_URI, newDocumentUri);
 
+        } else if (METHOD_CREATE_WEB_LINK_INTENT.equals(method)) {
+            enforceWritePermissionInner(documentUri, getCallingPackage(), null);
+
+            final Bundle options = extras.getBundle(DocumentsContract.EXTRA_OPTIONS);
+            final IntentSender intentSender = createWebLinkIntent(documentId, options);
+
+            out.putParcelable(DocumentsContract.EXTRA_RESULT, intentSender);
+
         } else if (METHOD_RENAME_DOCUMENT.equals(method)) {
             enforceWritePermissionInner(documentUri, getCallingPackage(), null);
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 794e1474..371c0f3 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5313,6 +5313,21 @@
         public static final String ACCESSIBILITY_ENABLED = "accessibility_enabled";
 
         /**
+         * Setting specifying if the accessibility shortcut dialog has been shown to this user.
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN =
+                "accessibility_shortcut_dialog_shown";
+
+        /**
+         * Setting specifying the the accessibility service to be toggled via the accessibility
+         * shortcut. Must be its flattened {@link ComponentName}.
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SHORTCUT_TARGET_SERVICE =
+                "accessibility_shortcut_target_service";
+
+        /**
          * If touch exploration is enabled.
          */
         public static final String TOUCH_EXPLORATION_ENABLED = "touch_exploration_enabled";
@@ -6746,6 +6761,14 @@
         public static final String DEVICE_PAIRED = "device_paired";
 
         /**
+         * Integer state indicating whether package verifier is enabled.
+         * TODO(b/34259924): Remove this setting.
+         *
+         * @hide
+         */
+        public static final String PACKAGE_VERIFIER_STATE = "package_verifier_state";
+
+        /**
          * This are the settings to be backed up.
          *
          * NOTE: Settings are backed up and restored in the order they appear
@@ -6774,6 +6797,8 @@
             TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
             TOUCH_EXPLORATION_ENABLED,
             ACCESSIBILITY_ENABLED,
+            ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+            ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN,
             ACCESSIBILITY_SPEAK_PASSWORD,
             ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED,
             ACCESSIBILITY_CAPTIONING_PRESET,
@@ -7063,7 +7088,9 @@
          * Setting whether the global gesture for enabling accessibility is enabled.
          * If this gesture is enabled the user will be able to perfrom it to enable
          * the accessibility state without visiting the settings app.
+         *
          * @hide
+         * No longer used. Should be removed once all dependencies have been updated.
          */
         public static final String ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED =
                 "enable_accessibility_global_gesture_enabled";
@@ -8011,6 +8038,16 @@
         public static final String NETWORK_RECOMMENDATIONS_ENABLED =
                 "network_recommendations_enabled";
 
+        /**
+         * The number of milliseconds the {@link com.android.server.NetworkScoreService}
+         * will give a recommendation request to complete before returning a default response.
+         *
+         * Type: long
+         * @hide
+         */
+        public static final String NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS =
+                "network_recommendation_request_timeout_ms";
+
        /**
         * Settings to allow BLE scans to be enabled even when Bluetooth is turned off for
         * connectivity.
@@ -9354,7 +9391,6 @@
             DOCK_SOUNDS_ENABLED,
             CHARGING_SOUNDS_ENABLED,
             USB_MASS_STORAGE_ENABLED,
-            ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED,
             WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON,
             WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY,
             WIFI_WATCHDOG_POOR_NETWORK_TEST_ENABLED,
diff --git a/core/java/android/service/autofill/AutoFillService.java b/core/java/android/service/autofill/AutoFillService.java
index c2e980c..805d8e5 100644
--- a/core/java/android/service/autofill/AutoFillService.java
+++ b/core/java/android/service/autofill/AutoFillService.java
@@ -61,6 +61,19 @@
     @SdkConstant(SdkConstant.SdkConstantType.SERVICE_ACTION)
     public static final String SERVICE_INTERFACE = "android.service.autofill.AutoFillService";
 
+    /**
+     * Name under which a AutoFillService component publishes information about itself.
+     * This meta-data should reference an XML resource containing a
+     * <code>&lt;{@link
+     * android.R.styleable#AutoFillService autofill-service}&gt;</code> tag.
+     * This is a a sample XML file configuring an AutoFillService:
+     * <pre> &lt;autofill-service
+     *     android:settingsActivity="foo.bar.SettingsActivity"
+     *     . . .
+     * /&gt;</pre>
+     */
+    public static final String SERVICE_META_DATA = "android.autofill";
+
     // Internal bundle keys.
     /** @hide */ public static final String KEY_CALLBACK = "callback";
     /** @hide */ public static final String KEY_SAVABLE_IDS = "savable_ids";
diff --git a/core/java/android/service/autofill/AutoFillServiceInfo.java b/core/java/android/service/autofill/AutoFillServiceInfo.java
index fe21615..ab86580 100644
--- a/core/java/android/service/autofill/AutoFillServiceInfo.java
+++ b/core/java/android/service/autofill/AutoFillServiceInfo.java
@@ -16,20 +16,34 @@
 package android.service.autofill;
 
 import android.Manifest;
+import android.annotation.Nullable;
 import android.app.AppGlobals;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
 import android.os.RemoteException;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.Xml;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
 
 /** @hide */
 public final class AutoFillServiceInfo {
+    static final String TAG = "AutoFillServiceInfo";
 
     private static ServiceInfo getServiceInfoOrThrow(ComponentName comp, int userHandle)
             throws PackageManager.NameNotFoundException {
         try {
-            final ServiceInfo si =
-                    AppGlobals.getPackageManager().getServiceInfo(comp, 0, userHandle);
+            ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(
+                    comp,
+                    PackageManager.GET_META_DATA,
+                    userHandle);
             if (si != null) {
                 return si;
             }
@@ -38,11 +52,21 @@
         throw new PackageManager.NameNotFoundException(comp.toString());
     }
 
+    @Nullable
     private String mParseError;
 
+    @Nullable
     private ServiceInfo mServiceInfo;
+    @Nullable
+    private String mSettingsActivity;
 
-    private  AutoFillServiceInfo(ServiceInfo si) {
+    public AutoFillServiceInfo(PackageManager pm, ComponentName comp, int userHandle)
+            throws PackageManager.NameNotFoundException {
+        this(pm, getServiceInfoOrThrow(comp, userHandle));
+    }
+
+    public AutoFillServiceInfo(PackageManager pm, ServiceInfo si)
+            throws PackageManager.NameNotFoundException{
         if (si == null) {
             mParseError = "Service not available";
             return;
@@ -53,19 +77,57 @@
             return;
         }
 
+        XmlResourceParser parser = null;
+        try {
+            parser = si.loadXmlMetaData(pm, AutoFillService.SERVICE_META_DATA);
+            if (parser == null) {
+                mParseError = "No " + AutoFillService.SERVICE_META_DATA
+                        + " meta-data for " + si.packageName;
+                return;
+            }
+
+            Resources res = pm.getResourcesForApplication(si.applicationInfo);
+
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            int type;
+            while ((type=parser.next()) != XmlPullParser.END_DOCUMENT
+                    && type != XmlPullParser.START_TAG) {
+            }
+
+            String nodeName = parser.getName();
+            if (!"autofill-service".equals(nodeName)) {
+                mParseError = "Meta-data does not start with autofill-service tag";
+                return;
+            }
+
+            TypedArray array = res.obtainAttributes(attrs,
+                    com.android.internal.R.styleable.AutoFillService);
+            mSettingsActivity = array.getString(
+                    com.android.internal.R.styleable.AutoFillService_settingsActivity);
+            array.recycle();
+        } catch (XmlPullParserException | IOException | PackageManager.NameNotFoundException e) {
+            mParseError = "Error parsing auto fill service meta-data: " + e;
+            Log.w(TAG, "error parsing auto fill service meta-data", e);
+            return;
+        } finally {
+            if (parser != null) parser.close();
+        }
         mServiceInfo = si;
     }
 
-    public AutoFillServiceInfo(ComponentName comp, int userHandle)
-            throws PackageManager.NameNotFoundException {
-        this(getServiceInfoOrThrow(comp, userHandle));
-    }
-
+    @Nullable
     public String getParseError() {
         return mParseError;
     }
 
+    @Nullable
     public ServiceInfo getServiceInfo() {
         return mServiceInfo;
     }
+
+    @Nullable
+    public String getSettingsActivity() {
+        return mSettingsActivity;
+    }
 }
diff --git a/core/java/android/util/ByteStringUtils.java b/core/java/android/util/ByteStringUtils.java
new file mode 100644
index 0000000..7103e6d
--- /dev/null
+++ b/core/java/android/util/ByteStringUtils.java
@@ -0,0 +1,82 @@
+/*
+ * 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.util;
+
+/**
+ * A utility class for common byte array to hex string operations and vise versa.
+ *
+ * @hide
+ */
+public final class ByteStringUtils {
+  private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+
+  private ByteStringUtils() {
+    /* hide constructor */
+  }
+
+  /**
+   * Returns the hex encoded string representation of bytes.
+   * @param bytes Byte array to encode.
+   * @return Hex encoded string representation of bytes.
+   */
+  public static String toString(byte[] bytes) {
+    if (bytes == null || bytes.length == 0 || bytes.length % 2 != 0) {
+      return null;
+    }
+
+    final int byteLength = bytes.length;
+    final int charCount = 2 * byteLength;
+    final char[] chars = new char[charCount];
+
+    for (int i = 0; i < byteLength; i++) {
+      final int byteHex = bytes[i] & 0xFF;
+      chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
+      chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
+    }
+    return new String(chars);
+  }
+
+  /**
+   * Returns the decoded byte array representation of str.
+   * @param str Hex encoded string to decode.
+   * @return Decoded byte array representation of str.
+   */
+  public static byte[] toByteArray(String str) {
+    if (str == null || str.length() == 0 || str.length() % 2 != 0) {
+      return null;
+    }
+
+    final char[] chars = str.toCharArray();
+    final int charLength = chars.length;
+    final byte[] bytes = new byte[charLength / 2];
+
+    for (int i = 0; i < bytes.length; i++) {
+      bytes[i] =
+          (byte)(((getIndex(chars[i * 2]) << 4) & 0xF0) | (getIndex(chars[i * 2 + 1]) & 0x0F));
+    }
+    return bytes;
+  }
+
+  private static int getIndex(char c) {
+    for (int i = 0; i < HEX_ARRAY.length; i++) {
+      if (HEX_ARRAY[i] == c) {
+        return i;
+      }
+    }
+    return -1;
+  }
+}
diff --git a/core/java/android/util/PackageUtils.java b/core/java/android/util/PackageUtils.java
index 6531aef..3181979 100644
--- a/core/java/android/util/PackageUtils.java
+++ b/core/java/android/util/PackageUtils.java
@@ -30,7 +30,6 @@
  * @hide
  */
 public final class PackageUtils {
-    private final static char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
 
     private PackageUtils() {
         /* hide constructor */
@@ -81,16 +80,6 @@
 
         messageDigest.update(data);
 
-        final byte[] digest = messageDigest.digest();
-        final int digestLength = digest.length;
-        final int charCount = 2 * digestLength;
-
-        final char[] chars = new char[charCount];
-        for (int i = 0; i < digestLength; i++) {
-            final int byteHex = digest[i] & 0xFF;
-            chars[i * 2] = HEX_ARRAY[byteHex >>> 4];
-            chars[i * 2 + 1] = HEX_ARRAY[byteHex & 0x0F];
-        }
-        return new String(chars);
+        return ByteStringUtils.toString(messageDigest.digest());
     }
 }
diff --git a/core/java/android/util/proto/ProtoOutputStream.java b/core/java/android/util/proto/ProtoOutputStream.java
index 81251fc..adf4938 100644
--- a/core/java/android/util/proto/ProtoOutputStream.java
+++ b/core/java/android/util/proto/ProtoOutputStream.java
@@ -928,7 +928,10 @@
 
     /**
      * Write a single proto "double" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeDouble(long fieldId, double val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_DOUBLE);
@@ -945,7 +948,10 @@
 
     /**
      * Write a single repeated proto "double" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedDouble(long fieldId, double val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_DOUBLE);
@@ -960,7 +966,10 @@
 
     /**
      * Write a list of packed proto "double" type field values.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedDouble(long fieldId, double[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_DOUBLE);
@@ -983,7 +992,10 @@
 
     /**
      * Write a single proto "float" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeFloat(long fieldId, float val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FLOAT);
@@ -1000,7 +1012,10 @@
 
     /**
      * Write a single repeated proto "float" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedFloat(long fieldId, float val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FLOAT);
@@ -1015,7 +1030,10 @@
 
     /**
      * Write a list of packed proto "float" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedFloat(long fieldId, float[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FLOAT);
@@ -1061,7 +1079,10 @@
      * Note that these are stored in memory as signed values and written as unsigned
      * varints, which if negative, are 10 bytes long. If you know the data is likely
      * to be negative, use "sint32".
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeInt32(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_INT32);
@@ -1082,7 +1103,10 @@
      * Note that these are stored in memory as signed values and written as unsigned
      * varints, which if negative, are 10 bytes long. If you know the data is likely
      * to be negative, use "sint32".
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedInt32(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_INT32);
@@ -1101,7 +1125,10 @@
      * Note that these are stored in memory as signed values and written as unsigned
      * varints, which if negative, are 10 bytes long. If you know the data is likely
      * to be negative, use "sint32".
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedInt32(long fieldId, int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT32);
@@ -1130,7 +1157,10 @@
 
     /**
      * Write a single proto "int64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeInt64(long fieldId, long val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_INT64);
@@ -1147,7 +1177,10 @@
 
     /**
      * Write a single repeated proto "int64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedInt64(long fieldId, long val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_INT64);
@@ -1162,7 +1195,10 @@
 
     /**
      * Write a list of packed proto "int64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedInt64(long fieldId, long[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_INT64);
@@ -1190,7 +1226,10 @@
 
     /**
      * Write a single proto "uint32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeUInt32(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_UINT32);
@@ -1207,7 +1246,10 @@
 
     /**
      * Write a single repeated proto "uint32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedUInt32(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_UINT32);
@@ -1222,7 +1264,10 @@
 
     /**
      * Write a list of packed proto "uint32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedUInt32(long fieldId, int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT32);
@@ -1250,7 +1295,10 @@
 
     /**
      * Write a single proto "uint64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeUInt64(long fieldId, long val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_UINT64);
@@ -1267,7 +1315,10 @@
 
     /**
      * Write a single proto "uint64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedUInt64(long fieldId, long val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_UINT64);
@@ -1282,7 +1333,10 @@
 
     /**
      * Write a single proto "uint64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedUInt64(long fieldId, long[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_UINT64);
@@ -1310,7 +1364,10 @@
 
     /**
      * Write a single proto "sint32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeSInt32(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SINT32);
@@ -1327,7 +1384,10 @@
 
     /**
      * Write a single repeated proto "sint32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedSInt32(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SINT32);
@@ -1342,7 +1402,10 @@
 
     /**
      * Write a list of packed proto "sint32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedSInt32(long fieldId, int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT32);
@@ -1370,7 +1433,10 @@
 
     /**
      * Write a single proto "sint64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeSInt64(long fieldId, long val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SINT64);
@@ -1387,7 +1453,10 @@
 
     /**
      * Write a single repeated proto "sint64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedSInt64(long fieldId, long val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SINT64);
@@ -1402,7 +1471,10 @@
 
     /**
      * Write a list of packed proto "sint64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedSInt64(long fieldId, long[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SINT64);
@@ -1429,7 +1501,10 @@
 
     /**
      * Write a single proto "fixed32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeFixed32(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED32);
@@ -1446,7 +1521,10 @@
 
     /**
      * Write a single repeated proto "fixed32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedFixed32(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED32);
@@ -1461,7 +1539,10 @@
 
     /**
      * Write a list of packed proto "fixed32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedFixed32(long fieldId, int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED32);
@@ -1484,7 +1565,10 @@
 
     /**
      * Write a single proto "fixed64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeFixed64(long fieldId, long val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_FIXED64);
@@ -1501,7 +1585,10 @@
 
     /**
      * Write a single repeated proto "fixed64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedFixed64(long fieldId, long val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_FIXED64);
@@ -1516,7 +1603,10 @@
 
     /**
      * Write a list of packed proto "fixed64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedFixed64(long fieldId, long[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_FIXED64);
@@ -1538,7 +1628,10 @@
     //
     /**
      * Write a single proto "sfixed32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeSFixed32(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED32);
@@ -1555,7 +1648,10 @@
 
     /**
      * Write a single repeated proto "sfixed32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedSFixed32(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED32);
@@ -1570,7 +1666,10 @@
 
     /**
      * Write a list of packed proto "sfixed32" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedSFixed32(long fieldId, int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED32);
@@ -1593,7 +1692,10 @@
 
     /**
      * Write a single proto "sfixed64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeSFixed64(long fieldId, long val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_SFIXED64);
@@ -1610,7 +1712,10 @@
 
     /**
      * Write a single repeated proto "sfixed64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedSFixed64(long fieldId, long val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_SFIXED64);
@@ -1625,7 +1730,10 @@
 
     /**
      * Write a list of packed proto "sfixed64" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedSFixed64(long fieldId, long[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_SFIXED64);
@@ -1648,7 +1756,10 @@
 
     /**
      * Write a single proto "bool" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeBool(long fieldId, boolean val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BOOL);
@@ -1666,7 +1777,10 @@
 
     /**
      * Write a single repeated proto "bool" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedBool(long fieldId, boolean val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BOOL);
@@ -1681,7 +1795,10 @@
 
     /**
      * Write a list of packed proto "bool" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedBool(long fieldId, boolean[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_BOOL);
@@ -1708,7 +1825,10 @@
 
     /**
      * Write a single proto "string" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeString(long fieldId, String val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_STRING);
@@ -1724,7 +1844,10 @@
 
     /**
      * Write a single repeated proto "string" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedString(long fieldId, String val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_STRING);
@@ -1763,7 +1886,10 @@
 
     /**
      * Write a single proto "bytes" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeBytes(long fieldId, byte[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_BYTES);
@@ -1780,7 +1906,10 @@
 
     /**
      * Write a single repeated proto "bytes" type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedBytes(long fieldId, byte[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_BYTES);
@@ -1803,7 +1932,10 @@
 
     /**
      * Write a single proto enum type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeEnum(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_ENUM);
@@ -1820,7 +1952,10 @@
 
     /**
      * Write a single repeated proto enum type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedEnum(long fieldId, int val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_ENUM);
@@ -1835,7 +1970,10 @@
 
     /**
      * Write a list of packed proto enum type field value.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writePackedEnum(long fieldId, int[] val) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_PACKED | FIELD_TYPE_ENUM);
@@ -1948,7 +2086,10 @@
      *
      * Returns a token which should be passed to endObject.  Calls to endObject must be
      * nested properly.
+     *
+     * @deprecated Use #start() instead.
      */
+    @Deprecated
     public long startObject(long fieldId) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT);
@@ -1958,7 +2099,10 @@
 
     /**
      * End a child object. Pass in the token from the correspoinding startObject call.
+     *
+     * @deprecated Use #end() instead.
      */
+    @Deprecated
     public void endObject(long token) {
         assertNotCompacted();
 
@@ -1970,7 +2114,10 @@
      *
      * Returns a token which should be passed to endObject.  Calls to endObject must be
      * nested properly.
+     *
+     * @deprecated Use #start() instead.
      */
+    @Deprecated
     public long startRepeatedObject(long fieldId) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT);
@@ -1980,7 +2127,10 @@
 
     /**
      * End a child object. Pass in the token from the correspoinding startRepeatedObject call.
+     *
+     * @deprecated Use #end() instead.
      */
+    @Deprecated
     public void endRepeatedObject(long token) {
         assertNotCompacted();
 
@@ -2062,7 +2212,10 @@
 
     /**
      * Write an object that has already been flattend.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeObject(long fieldId, byte[] value) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_SINGLE | FIELD_TYPE_OBJECT);
@@ -2070,7 +2223,7 @@
         writeObjectImpl(id, value);
     }
 
-    public void writeObjectImpl(int id, byte[] value) {
+    void writeObjectImpl(int id, byte[] value) {
         if (value != null && value.length != 0) {
             writeKnownLengthHeader(id, value.length);
             mBuffer.writeRawBuffer(value);
@@ -2079,7 +2232,10 @@
 
     /**
      * Write an object that has already been flattend.
+     *
+     * @deprecated Use #write instead.
      */
+    @Deprecated
     public void writeRepeatedObject(long fieldId, byte[] value) {
         assertNotCompacted();
         final int id = checkFieldId(fieldId, FIELD_COUNT_REPEATED | FIELD_TYPE_OBJECT);
@@ -2087,7 +2243,7 @@
         writeRepeatedObjectImpl(id, value);
     }
 
-    public void writeRepeatedObjectImpl(int id, byte[] value) {
+    void writeRepeatedObjectImpl(int id, byte[] value) {
         writeKnownLengthHeader(id, value == null ? 0 : value.length);
         mBuffer.writeRawBuffer(value);
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 9d1af50..37dfdb9 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -6934,8 +6934,7 @@
                 & (View.AUTO_FILL_FLAG_TYPE_FILL
                         | View.AUTO_FILL_FLAG_TYPE_SAVE)) != 0;
         final int id = mID;
-        if (id > 0 && (id&0xff000000) != 0 && (id&0x00ff0000) != 0
-                && (id&0x0000ffff) != 0) {
+        if (id != NO_ID && !isViewIdGenerated(id)) {
             String pkg, type, entry;
             try {
                 final Resources res = getResources();
@@ -22640,6 +22639,10 @@
         }
     }
 
+    private static boolean isViewIdGenerated(int id) {
+        return (id & 0xFF000000) == 0 && (id & 0x00FFFFFF) != 0;
+    }
+
     /**
      * Gets the Views in the hierarchy affected by entering and exiting Activity Scene transitions.
      * @param transitioningViews This View will be added to transitioningViews if it is VISIBLE and
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 6d2f850..0e753f3 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -83,6 +83,13 @@
     private static final int GLOBAL_ACTIONS_KEY_TIMEOUT = 500;
 
     /**
+     * Defines the duration in milliseconds a user needs to hold down the
+     * appropriate button to bring up the accessibility shortcut (first time) or enable it
+     * (once shortcut is configured).
+     */
+    private static final int A11Y_SHORTCUT_KEY_TIMEOUT = 3000;
+
+    /**
      * Defines the duration in milliseconds we will wait to see if a touch event
      * is a tap or a scroll. If the user does not move within this interval, it is
      * considered to be a tap.
@@ -785,6 +792,18 @@
     }
 
     /**
+     * The amount of time a user needs to press the relevant keys to activate the accessibility
+     * shortcut.
+     *
+     * @return how long a user needs to press the relevant keys to activate the accessibility
+     *   shortcut.
+     * @hide
+     */
+    public long getAccessibilityShortcutKeyTimeout() {
+        return A11Y_SHORTCUT_KEY_TIMEOUT;
+    }
+
+    /**
      * The amount of friction applied to scrolls and flings.
      *
      * @return A scalar dimensionless value representing the coefficient of
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 1b42a90..a479bb3 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1788,15 +1788,15 @@
             for (int i = childrenCount - 1; i >= 0; i--) {
                 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
-                final PointF point = getLocalPoint();
-                if (isTransformedTouchPointInView(x, y, child, point)) {
-                    final PointerIcon pointerIcon =
-                            dispatchResolvePointerIcon(event, pointerIndex, child);
-                    if (pointerIcon != null) {
-                        if (preorderedList != null) preorderedList.clear();
-                        return pointerIcon;
-                    }
-                    break;
+                if (!canViewReceivePointerEvents(child)
+                        || !isTransformedTouchPointInView(x, y, child, null)) {
+                    continue;
+                }
+                final PointerIcon pointerIcon =
+                        dispatchResolvePointerIcon(event, pointerIndex, child);
+                if (pointerIcon != null) {
+                    if (preorderedList != null) preorderedList.clear();
+                    return pointerIcon;
                 }
             }
             if (preorderedList != null) preorderedList.clear();
@@ -2091,11 +2091,12 @@
                                 getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                         final View child =
                                 getAndVerifyPreorderedView(preorderedList, children, childIndex);
-                        final PointF point = getLocalPoint();
-                        if (isTransformedTouchPointInView(x, y, child, point)) {
-                            if (dispatchTooltipHoverEvent(event, child)) {
-                                newTarget = child;
-                            }
+                        if (!canViewReceivePointerEvents(child)
+                                || !isTransformedTouchPointInView(x, y, child, null)) {
+                            continue;
+                        }
+                        if (dispatchTooltipHoverEvent(event, child)) {
+                            newTarget = child;
                             break;
                         }
                     }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9ddbbf2..c0f2c37 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1724,6 +1724,7 @@
         final int surfaceGenerationId = mSurface.getGenerationId();
 
         final boolean isViewVisible = viewVisibility == View.VISIBLE;
+        final boolean windowRelayoutWasForced = mForceNextWindowRelayout;
         if (mFirst || windowShouldResize || insetsChanged ||
                 viewVisibilityChanged || params != null || mForceNextWindowRelayout) {
             mForceNextWindowRelayout = false;
@@ -1888,7 +1889,7 @@
                         mAttachInfo.mThreadedRenderer.destroy();
                     }
                 } else if ((surfaceGenerationId != mSurface.getGenerationId()
-                        || surfaceSizeChanged)
+                        || surfaceSizeChanged || windowRelayoutWasForced)
                         && mSurfaceHolder == null
                         && mAttachInfo.mThreadedRenderer != null) {
                     mFullRedrawNeeded = true;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 7f940f1..bfb8d83 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -21,6 +21,7 @@
 import android.Manifest;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.NonNull;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
@@ -241,6 +242,8 @@
      * @hide
      */
     public AccessibilityManager(Context context, IAccessibilityManager service, int userId) {
+        // Constructor can't be chained because we can't create an instance of an inner class
+        // before calling another constructor.
         mHandler = new MyHandler(context.getMainLooper());
         mUserId = userId;
         synchronized (mLock) {
@@ -249,6 +252,23 @@
     }
 
     /**
+     * Create an instance.
+     *
+     * @param handler The handler to use
+     * @param service An interface to the backing service.
+     * @param userId User id under which to run.
+     *
+     * @hide
+     */
+    public AccessibilityManager(Handler handler, IAccessibilityManager service, int userId) {
+        mHandler = handler;
+        mUserId = userId;
+        synchronized (mLock) {
+            tryConnectToServiceLocked(service);
+        }
+    }
+
+    /**
      * @hide
      */
     public IAccessibilityManagerClient getClient() {
@@ -647,6 +667,30 @@
     }
 
     /**
+     * Find an installed service with the specified {@link ComponentName}.
+     *
+     * @param componentName The name to match to the service.
+     *
+     * @return The info corresponding to the installed service, or {@code null} if no such service
+     * is installed.
+     * @hide
+     */
+    public AccessibilityServiceInfo getInstalledServiceInfoWithComponentName(
+            ComponentName componentName) {
+        final List<AccessibilityServiceInfo> installedServiceInfos =
+                getInstalledAccessibilityServiceList();
+        if ((installedServiceInfos == null) || (componentName == null)) {
+            return null;
+        }
+        for (int i = 0; i < installedServiceInfos.size(); i++) {
+            if (componentName.equals(installedServiceInfos.get(i).getComponentName())) {
+                return installedServiceInfos.get(i);
+            }
+        }
+        return null;
+    }
+
+    /**
      * Adds an accessibility interaction connection interface for a given window.
      * @param windowToken The window token to which a connection is added.
      * @param connection The connection.
@@ -693,6 +737,26 @@
         }
     }
 
+    /**
+     * Perform the accessibility shortcut if the caller has permission.
+     *
+     * @hide
+     */
+    public void performAccessibilityShortcut() {
+        final IAccessibilityManager service;
+        synchronized (mLock) {
+            service = getServiceLocked();
+            if (service == null) {
+                return;
+            }
+        }
+        try {
+            service.performAccessibilityShortcut();
+        } catch (RemoteException re) {
+            Log.e(LOG_TAG, "Error performing accessibility shortcut. ", re);
+        }
+    }
+
     private IAccessibilityManager getServiceLocked() {
         if (mService == null) {
             tryConnectToServiceLocked(null);
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 91468da..f0bf7e5 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -557,6 +557,8 @@
 
     private static final int BOOLEAN_PROPERTY_IMPORTANCE = 0x0040000;
 
+    private static final int BOOLEAN_PROPERTY_IS_SHOWING_HINT = 0x0100000;
+
     /**
      * Bits that provide the id of a virtual descendant of a view.
      */
@@ -645,6 +647,7 @@
     // Hidden, unparceled value used to hold the original value passed to setText
     private CharSequence mOriginalText;
     private CharSequence mText;
+    private CharSequence mHintText;
     private CharSequence mError;
     private CharSequence mContentDescription;
     private String mViewIdResourceName;
@@ -2176,6 +2179,33 @@
     }
 
     /**
+     * Returns whether the node's text represents a hint for the user to enter text. It should only
+     * be {@code true} if the node has editable text.
+     *
+     * @return {@code true} if the text in the node represents a hint to the user, {@code false}
+     * otherwise.
+     */
+    public boolean isShowingHintText() {
+        return getBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT);
+    }
+
+    /**
+     * Sets whether the node's text represents a hint for the user to enter text. It should only
+     * be {@code true} if the node has editable text.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param showingHintText {@code true} if the text in the node represents a hint to the user,
+     * {@code false} otherwise.
+     */
+    public void setShowingHintText(boolean showingHintText) {
+        setBooleanProperty(BOOLEAN_PROPERTY_IS_SHOWING_HINT, showingHintText);
+    }
+
+    /**
      * Gets the package this node comes from.
      *
      * @return The package name.
@@ -2317,6 +2347,32 @@
     }
 
     /**
+     * Gets the hint text of this node. Only applies to nodes where text can be entered.
+     *
+     * @return The hint text.
+     */
+    public CharSequence getHintText() {
+        return mHintText;
+    }
+
+    /**
+     * Sets the hint text of this node. Only applies to nodes where text can be entered.
+     * <p>
+     *   <strong>Note:</strong> Cannot be called from an
+     *   {@link android.accessibilityservice.AccessibilityService}.
+     *   This class is made immutable before being delivered to an AccessibilityService.
+     * </p>
+     *
+     * @param hintText The hint text for this mode.
+     *
+     * @throws IllegalStateException If called from an AccessibilityService.
+     */
+    public void setHintText(CharSequence hintText) {
+        enforceNotSealed();
+        mHintText = (hintText == null) ? null : hintText.subSequence(0, hintText.length());
+    }
+
+    /**
      * Sets the error text of this node.
      * <p>
      *   <strong>Note:</strong> Cannot be called from an
@@ -2889,6 +2945,7 @@
         parcel.writeCharSequence(mPackageName);
         parcel.writeCharSequence(mClassName);
         parcel.writeCharSequence(mText);
+        parcel.writeCharSequence(mHintText);
         parcel.writeCharSequence(mError);
         parcel.writeCharSequence(mContentDescription);
         parcel.writeString(mViewIdResourceName);
@@ -2963,6 +3020,7 @@
         mPackageName = other.mPackageName;
         mClassName = other.mClassName;
         mText = other.mText;
+        mHintText = other.mHintText;
         mError = other.mError;
         mContentDescription = other.mContentDescription;
         mViewIdResourceName = other.mViewIdResourceName;
@@ -3066,6 +3124,7 @@
         mPackageName = parcel.readCharSequence();
         mClassName = parcel.readCharSequence();
         mText = parcel.readCharSequence();
+        mHintText = parcel.readCharSequence();
         mError = parcel.readCharSequence();
         mContentDescription = parcel.readCharSequence();
         mViewIdResourceName = parcel.readString();
@@ -3137,6 +3196,7 @@
         mPackageName = null;
         mClassName = null;
         mText = null;
+        mHintText = null;
         mError = null;
         mContentDescription = null;
         mViewIdResourceName = null;
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 2829744..ed77f68 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -60,7 +60,6 @@
 
     IBinder getWindowToken(int windowId, int userId);
 
-    void enableAccessibilityService(in ComponentName service, int userId);
-
-    void disableAccessibilityService(in ComponentName service, int userId);
+    // Requires WRITE_SECURE_SETTINGS
+    void performAccessibilityShortcut();
 }
diff --git a/core/java/android/webkit/IWebViewUpdateService.aidl b/core/java/android/webkit/IWebViewUpdateService.aidl
index 894f080..dbca7ff 100644
--- a/core/java/android/webkit/IWebViewUpdateService.aidl
+++ b/core/java/android/webkit/IWebViewUpdateService.aidl
@@ -78,4 +78,14 @@
      * Enable or disable the WebView package fallback mechanism.
      */
     void enableFallbackLogic(boolean enable);
+
+    /**
+     * Used by Settings to determine whether multiprocess is enabled.
+     */
+    boolean isMultiProcessEnabled();
+
+    /**
+     * Used by Settings to enable/disable multiprocess.
+     */
+    void enableMultiProcess(boolean enable);
 }
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 2703d6e..2fc8ec9 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2480,7 +2480,7 @@
     }
 
     void onDrop(DragEvent event) {
-        StringBuilder content = new StringBuilder("");
+        SpannableStringBuilder content = new SpannableStringBuilder();
 
         final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event);
         if (permissions != null) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 984fa04..b6693c7 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -7740,14 +7740,25 @@
             desired = Math.max(desired, dr.mDrawableHeightRight);
         }
 
-        desired += getCompoundPaddingTop() + getCompoundPaddingBottom();
+        int linecount = layout.getLineCount();
+        final int padding = getCompoundPaddingTop() + getCompoundPaddingBottom();
+        desired += padding;
 
         if (mMaxMode != LINES) {
             desired = Math.min(desired, mMaximum);
+        } else if (cap && linecount > mMaximum && layout instanceof DynamicLayout) {
+            desired = layout.getLineTop(mMaximum);
+
+            if (dr != null) {
+                desired = Math.max(desired, dr.mDrawableHeightLeft);
+                desired = Math.max(desired, dr.mDrawableHeightRight);
+            }
+
+            desired += padding;
+            linecount = mMaximum;
         }
 
         if (mMinMode == LINES) {
-            int linecount = layout.getLineCount();
             if (linecount < mMinimum) {
                 desired += getLineHeight() * (mMinimum - linecount);
             }
@@ -9632,6 +9643,8 @@
         final boolean isPassword = hasPasswordTransformationMethod();
         info.setPassword(isPassword);
         info.setText(getTextForAccessibility());
+        info.setHintText(mHint);
+        info.setShowingHintText(isShowingHint());
 
         if (mBufferType == BufferType.EDITABLE) {
             info.setEditable(true);
diff --git a/core/java/com/android/internal/logging/LogBuilder.java b/core/java/com/android/internal/logging/LogBuilder.java
index 8e2e114..7eda3da 100644
--- a/core/java/com/android/internal/logging/LogBuilder.java
+++ b/core/java/com/android/internal/logging/LogBuilder.java
@@ -1,6 +1,22 @@
+/*
+ * 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.internal.logging;
 
 import android.util.EventLog;
+import android.util.Log;
 import android.util.SparseArray;
 import android.view.View;
 
@@ -14,16 +30,16 @@
  */
 
 public class LogBuilder {
-
+    private static final String TAG = "LogBuilder";
     private SparseArray<Object> entries = new SparseArray();
 
     public LogBuilder(int mainCategory) {
         setCategory(mainCategory);
     }
 
-    public LogBuilder setView(View view) {
-        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_VIEW, view.getId());
-        return this;
+    /* Deserialize from the eventlog */
+    public LogBuilder(Object[] items) {
+      deserialize(items);
     }
 
     public LogBuilder setCategory(int category) {
@@ -36,16 +52,48 @@
         return this;
     }
 
+    public LogBuilder setSubtype(int subtype) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE, subtype);
+        return this;
+    }
+
+    public LogBuilder setTimestamp(long timestamp) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_TIMESTAMP, timestamp);
+        return this;
+    }
+
+    public LogBuilder setPackageName(String packageName) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME, packageName);
+        return this;
+    }
+
+    public LogBuilder setCounterName(String name) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_NAME, name);
+        return this;
+    }
+
+    public LogBuilder setCounterBucket(int bucket) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET, bucket);
+        return this;
+    }
+
+    public LogBuilder setCounterBucket(long bucket) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET, bucket);
+        return this;
+    }
+
+    public LogBuilder setCounterValue(int value) {
+        entries.put(MetricsEvent.RESERVED_FOR_LOGBUILDER_VALUE, value);
+        return this;
+    }
+
     /**
      * @param tag From your MetricsEvent enum.
      * @param value One of Integer, Long, Float, String
      * @return
      */
     public LogBuilder addTaggedData(int tag, Object value) {
-        if (!(value instanceof Integer ||
-            value instanceof String ||
-            value instanceof Long ||
-            value instanceof Float)) {
+        if (isValidValue(value)) {
             throw new IllegalArgumentException(
                     "Value must be loggable type - int, long, float, String");
         }
@@ -53,6 +101,94 @@
         return this;
     }
 
+    public boolean isValidValue(Object value) {
+        return !(value instanceof Integer ||
+            value instanceof String ||
+            value instanceof Long ||
+            value instanceof Float);
+    }
+
+    public Object getTaggedData(int tag) {
+        return entries.get(tag);
+    }
+
+    public int getCategory() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_CATEGORY);
+        if (obj instanceof Integer) {
+            return (Integer) obj;
+        } else {
+            return MetricsEvent.VIEW_UNKNOWN;
+        }
+    }
+
+    public int getType() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_TYPE);
+        if (obj instanceof Integer) {
+            return (Integer) obj;
+        } else {
+            return MetricsEvent.TYPE_UNKNOWN;
+        }
+    }
+
+    public int getSubtype() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_SUBTYPE);
+        if (obj instanceof Integer) {
+            return (Integer) obj;
+        } else {
+            return 0;
+        }
+    }
+
+    public long getTimestamp() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_TIMESTAMP);
+        if (obj instanceof Long) {
+            return (Long) obj;
+        } else {
+            return 0;
+        }
+    }
+
+    public String getPackageName() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_PACKAGENAME);
+        if (obj instanceof String) {
+            return (String) obj;
+        } else {
+            return null;
+        }
+    }
+
+    public String getCounterName() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_NAME);
+        if (obj instanceof String) {
+            return (String) obj;
+        } else {
+            return null;
+        }
+    }
+
+    public long getCounterBucket() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET);
+        if (obj instanceof Number) {
+            return ((Number) obj).longValue();
+        } else {
+            return 0L;
+        }
+    }
+
+    public boolean isLongCounterBucket() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_BUCKET);
+        return obj instanceof Long;
+    }
+
+    public int getCounterValue() {
+        Object obj = entries.get(MetricsEvent.RESERVED_FOR_LOGBUILDER_VALUE);
+        if (obj instanceof Integer) {
+            return (Integer) obj;
+        } else {
+            return 0;
+        }
+    }
+
     /**
      * Assemble logs into structure suitable for EventLog.
      */
@@ -64,5 +200,17 @@
         }
         return out;
     }
-}
 
+    public void deserialize(Object[] items) {
+        int i = 0;
+        while(i < items.length) {
+            Object key = items[i++];
+            Object value = i < items.length ? items[i++] : null;
+            if (key instanceof Integer) {
+                entries.put((Integer) key, value);
+            } else {
+              Log.i(TAG, "Invalid key " + key.toString());
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index 5eb39ae..16c2719 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -17,12 +17,10 @@
 
 import android.content.Context;
 import android.os.Build;
-import android.util.EventLog;
 import android.view.View;
 
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
-
 /**
  * Log all the things.
  *
@@ -38,6 +36,10 @@
             throw new IllegalArgumentException("Must define metric category");
         }
         EventLogTags.writeSysuiViewVisibility(category, 100);
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(category)
+                        .setType(MetricsEvent.TYPE_OPEN)
+                        .serialize());
     }
 
     public static void hidden(Context context, int category) throws IllegalArgumentException {
@@ -45,6 +47,10 @@
             throw new IllegalArgumentException("Must define metric category");
         }
         EventLogTags.writeSysuiViewVisibility(category, 0);
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(category)
+                        .setType(MetricsEvent.TYPE_CLOSE)
+                        .serialize());
     }
 
     public static void visibility(Context context, int category, boolean visibile)
@@ -62,21 +68,38 @@
     }
 
     public static void action(Context context, int category) {
-        action(context, category, "");
+        EventLogTags.writeSysuiAction(category, "");
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(category)
+                        .setType(MetricsEvent.TYPE_ACTION)
+                        .serialize());
     }
 
     public static void action(Context context, int category, int value) {
-        action(context, category, Integer.toString(value));
+        EventLogTags.writeSysuiAction(category, Integer.toString(value));
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(category)
+                        .setType(MetricsEvent.TYPE_ACTION)
+                        .setSubtype(value)
+                        .serialize());
     }
 
     public static void action(Context context, int category, boolean value) {
-        action(context, category, Boolean.toString(value));
+        EventLogTags.writeSysuiAction(category, Boolean.toString(value));
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(category)
+                        .setType(MetricsEvent.TYPE_ACTION)
+                        .setSubtype(value ? 1 : 0)
+                        .serialize());
     }
 
     public static void action(LogBuilder content) {
         //EventLog.writeEvent(524292, content.serialize());
         // Below would be the *right* way to do this, using the generated
         // EventLogTags method, but that doesn't work.
+        if (content.getType() == MetricsEvent.TYPE_UNKNOWN) {
+            content.setType(MetricsEvent.TYPE_ACTION);
+        }
         EventLogTags.writeSysuiMultiAction(content.serialize());
     }
 
@@ -86,15 +109,30 @@
             throw new IllegalArgumentException("Must define metric category");
         }
         EventLogTags.writeSysuiAction(category, pkg);
+        EventLogTags.writeSysuiMultiAction(new LogBuilder(category)
+                .setType(MetricsEvent.TYPE_ACTION)
+                .setPackageName(pkg)
+                .serialize());
     }
 
     /** Add an integer value to the monotonically increasing counter with the given name. */
     public static void count(Context context, String name, int value) {
         EventLogTags.writeSysuiCount(name, value);
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
+                        .setCounterName(name)
+                        .setCounterValue(value)
+                        .serialize());
     }
 
     /** Increment the bucket with the integer label on the histogram with the given name. */
     public static void histogram(Context context, String name, int bucket) {
         EventLogTags.writeSysuiHistogram(name, bucket);
+        EventLogTags.writeSysuiMultiAction(
+                new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
+                        .setCounterName(name)
+                        .setCounterBucket(bucket)
+                        .setCounterValue(1)
+                        .serialize());
     }
 }
diff --git a/core/java/com/android/internal/logging/MetricsReader.java b/core/java/com/android/internal/logging/MetricsReader.java
new file mode 100644
index 0000000..c4fc963
--- /dev/null
+++ b/core/java/com/android/internal/logging/MetricsReader.java
@@ -0,0 +1,64 @@
+/*
+ * 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.internal.logging;
+
+import com.android.internal.logging.legacy.LegacyConversionLogger;
+import com.android.internal.logging.legacy.EventLogCollector;
+
+import java.util.Queue;
+
+/**
+ * Read platform logs.
+ */
+public class MetricsReader {
+    private EventLogCollector mReader;
+    private Queue<LogBuilder> mEventQueue;
+    private long mLastEventMs;
+    private long mCheckpointMs;
+
+    /** Open a new session and start reading logs.
+     *
+     * Starts reading from the oldest log not already read by this reader object.
+     * On first invocation starts from the oldest available log ion the system.
+     */
+    public void read(long startMs) {
+        EventLogCollector reader = EventLogCollector.getInstance();
+        LegacyConversionLogger logger = new LegacyConversionLogger();
+        mLastEventMs = reader.collect(logger, startMs);
+        mEventQueue = logger.getEvents();
+    }
+
+    public void checkpoint() {
+        read(0L);
+        mCheckpointMs = mLastEventMs;
+        mEventQueue = null;
+    }
+
+    public void reset() {
+        read(mCheckpointMs);
+    }
+
+    /* Does the current log session have another entry? */
+    public boolean hasNext() {
+        return mEventQueue == null ? false : !mEventQueue.isEmpty();
+    }
+
+    /* Next entry in the current log session. */
+    public LogBuilder next() {
+        return mEventQueue == null ? null : mEventQueue.remove();
+    }
+
+}
diff --git a/core/java/com/android/internal/logging/legacy/CounterParser.java b/core/java/com/android/internal/logging/legacy/CounterParser.java
new file mode 100644
index 0000000..f318503
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/CounterParser.java
@@ -0,0 +1,54 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+/**
+ * Parse the Android counter event logs.
+ * @hide
+ */
+public class CounterParser extends TagParser {
+    private static final String TAG = "CounterParser";
+    private static final int EVENTLOG_TAG = 524290;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 2) {
+            try {
+                String name = ((String) operands[0]);
+                int value = (Integer) operands[1];
+                logCount(logger, name, value);
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.d(TAG, "unexpected operand type", e);
+                }
+            }
+        } else if (debug) {
+            Log.d(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+
+    protected void logCount(TronLogger logger, String name, int value) {
+        logger.incrementBy(TronCounters.TRON_AOSP_PREFIX + name, value);
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/EventLogCollector.java b/core/java/com/android/internal/logging/legacy/EventLogCollector.java
new file mode 100644
index 0000000..952ae23
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/EventLogCollector.java
@@ -0,0 +1,188 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.ArrayMap;
+import android.util.EventLog;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Scan the event log for interaction metrics events.
+ * @hide
+ */
+public class EventLogCollector {
+    private static final String TAG = "EventLogCollector";
+
+    // TODO replace this with GoogleLogTags.TRON_HEARTBEAT
+    @VisibleForTesting
+    static final int TRON_HEARTBEAT = 208000;
+
+    private static EventLogCollector sInstance;
+
+    private final ArrayMap<Integer, TagParser> mTagParsers;
+    private int[] mInterestingTags;
+
+    private LogReader mLogReader;
+
+    private EventLogCollector() {
+        mTagParsers = new ArrayMap<>();
+        addParser(new SysuiViewVisibilityParser());
+        addParser(new SysuiActionParser());
+        addParser(new SysuiQueryParser());
+        addParser(new NotificationPanelRevealedParser());
+        addParser(new NotificationPanelHiddenParser());
+        addParser(new NotificationClickedParser());
+        addParser(new NotificationActionClickedParser());
+        addParser(new NotificationCanceledParser());
+        addParser(new NotificationVisibilityParser());
+        addParser(new NotificationAlertParser());
+        addParser(new NotificationExpansionParser());
+        addParser(new CounterParser());
+        addParser(new HistogramParser());
+        addParser(new LockscreenGestureParser());
+        addParser(new StatusBarStateParser());
+        addParser(new PowerScreenStateParser());
+        addParser(new SysuiMultiActionParser());
+
+        mLogReader = new LogReader();
+    }
+
+    public static EventLogCollector getInstance() {
+        if (sInstance == null) {
+            sInstance = new EventLogCollector();
+        }
+        return sInstance;
+    }
+
+    @VisibleForTesting
+    public void setLogReader(LogReader logReader) {
+        mLogReader = logReader;
+    }
+
+    private int[] getInterestingTags() {
+        if (mInterestingTags == null) {
+            mInterestingTags = new int[mTagParsers.size()];
+            for (int i = 0; i < mTagParsers.size(); i++) {
+                mInterestingTags[i] = mTagParsers.valueAt(i).getTag();
+            }
+        }
+        return mInterestingTags;
+    }
+
+    // I would customize ArrayMap to add put(TagParser), but ArrayMap is final.
+    @VisibleForTesting
+    void addParser(TagParser parser) {
+        mTagParsers.put(parser.getTag(), parser);
+        mInterestingTags = null;
+    }
+
+    public void collect(LegacyConversionLogger logger) {
+        collect(logger, 0L);
+    }
+
+    public long collect(TronLogger logger, long lastSeenEventMs) {
+        long lastEventMs = 0L;
+        final boolean debug = Util.debug();
+
+        if (debug) {
+            Log.d(TAG, "Eventlog Collection");
+        }
+        ArrayList<Event> events = new ArrayList<>();
+        try {
+            mLogReader.readEvents(getInterestingTags(), events);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        if (debug) {
+            Log.d(TAG, "read this many events: " + events.size());
+        }
+
+        for (Event event : events) {
+            final long millis = event.getTimeNanos() / 1000000;
+            if (millis > lastSeenEventMs) {
+                final int tag = event.getTag();
+                TagParser parser = mTagParsers.get(tag);
+                if (parser == null) {
+                    if (debug) {
+                        Log.d(TAG, "unknown tag: " + tag);
+                    }
+                    continue;
+                }
+                if (debug) {
+                    Log.d(TAG, "parsing tag: " + tag);
+                }
+                parser.parseEvent(logger, event);
+                lastEventMs = Math.max(lastEventMs, millis);
+            } else {
+                if (debug) {
+                    Log.d(TAG, "old event: " + millis + " < " + lastSeenEventMs);
+                }
+            }
+        }
+        return lastEventMs;
+    }
+
+    @VisibleForTesting
+    static class Event {
+        long mTimeNanos;
+        int mTag;
+        Object mData;
+
+        Event(long timeNanos, int tag, Object data) {
+            super();
+            mTimeNanos = timeNanos;
+            mTag = tag;
+            mData = data;
+        }
+
+        Event(EventLog.Event event) {
+            mTimeNanos = event.getTimeNanos();
+            mTag = event.getTag();
+            mData = event.getData();
+        }
+
+        public long getTimeNanos() {
+            return mTimeNanos;
+        }
+
+        public int getTag() {
+            return mTag;
+        }
+
+        public Object getData() {
+            return mData;
+        }
+    }
+
+    @VisibleForTesting
+    static class LogReader {
+        public void readEvents(int[] tags, Collection<Event> events) throws IOException {
+            // Testing in Android: the Static Final Class Strikes Back!
+            ArrayList<EventLog.Event> nativeEvents = new ArrayList<>();
+            EventLog.readEvents(tags, nativeEvents);
+            for (EventLog.Event nativeEvent : nativeEvents) {
+                Event event = new Event(nativeEvent);
+                events.add(event);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/HistogramParser.java b/core/java/com/android/internal/logging/legacy/HistogramParser.java
new file mode 100644
index 0000000..bb7e75c
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/HistogramParser.java
@@ -0,0 +1,35 @@
+/*
+ * 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.internal.logging.legacy;
+
+/**
+ * Parse the Android histogram event logs.
+ * @hide
+ */
+public class HistogramParser extends CounterParser {
+    private static final String TAG = "HistogramParser";
+    private static final int EVENTLOG_TAG = 524291;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    protected void logCount(TronLogger logger, String name, int value) {
+        logger.incrementIntHistogram("tron_varz_" + name, value);
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java b/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java
new file mode 100644
index 0000000..7381ff0
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/LegacyConversionLogger.java
@@ -0,0 +1,111 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.os.Bundle;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.Queue;
+
+/** @hide */
+public class LegacyConversionLogger implements TronLogger {
+    public static final String VIEW_KEY = "view";
+    public static final String TYPE_KEY = "type";
+    public static final String EVENT_KEY = "data";
+
+    public static final int TYPE_COUNTER = 1;
+    public static final int TYPE_HISTOGRAM = 2;
+    public static final int TYPE_EVENT = 3;
+
+    private final Queue<LogBuilder> mQueue;
+    private HashMap<String, Boolean> mConfig;
+
+    public LegacyConversionLogger() {
+        mQueue = new LinkedList<>();
+    }
+
+    public Queue<LogBuilder> getEvents() {
+        return mQueue;
+    }
+
+    @Override
+    public void increment(String counterName) {
+        LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
+                .setCounterName(counterName)
+                .setCounterValue(1);
+        mQueue.add(b);
+    }
+
+    @Override
+    public void incrementBy(String counterName, int value) {
+        LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_COUNTER)
+                .setCounterName(counterName)
+                .setCounterValue(value);
+        mQueue.add(b);
+    }
+
+    @Override
+    public void incrementIntHistogram(String counterName, int bucket) {
+        LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
+                .setCounterName(counterName)
+                .setCounterBucket(bucket)
+                .setCounterValue(1);
+        mQueue.add(b);
+    }
+
+    @Override
+    public void incrementLongHistogram(String counterName, long bucket) {
+        LogBuilder b = new LogBuilder(MetricsEvent.RESERVED_FOR_LOGBUILDER_HISTOGRAM)
+                .setCounterName(counterName)
+                .setCounterBucket(bucket)
+                .setCounterValue(1);
+        mQueue.add(b);
+    }
+
+    @Override
+    public LogBuilder obtain() {
+        return new LogBuilder(MetricsEvent.VIEW_UNKNOWN);
+    }
+
+    @Override
+    public void dispose(LogBuilder proto) {
+    }
+
+    @Override
+    public void addEvent(LogBuilder proto) {
+        mQueue.add(proto);
+    }
+
+    @Override
+    public boolean getConfig(String configName) {
+        if (mConfig != null && mConfig.containsKey(configName)) {
+            return mConfig.get(configName);
+        }
+        return false;
+    }
+
+    @Override
+    public void setConfig(String configName, boolean newValue) {
+        if (mConfig == null) {
+            mConfig = new HashMap<>();
+        }
+        mConfig.put(configName, newValue);
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/LockscreenGestureParser.java b/core/java/com/android/internal/logging/legacy/LockscreenGestureParser.java
new file mode 100644
index 0000000..6bede24
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/LockscreenGestureParser.java
@@ -0,0 +1,80 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android lockscreen gesture logs.
+ * @hide
+ */
+public class LockscreenGestureParser extends TagParser {
+    private static final String TAG = "LockscreenGestureParser";
+    private static final int EVENTLOG_TAG = 36021;
+
+    // source of truth is com.android.systemui.EventLogConstants
+    public static final int[] GESTURE_TYPE_MAP = {
+            MetricsEvent.VIEW_UNKNOWN,  // there is no type 0
+            MetricsEvent.ACTION_LS_UNLOCK,  // SYSUI_LOCKSCREEN_GESTURE_SWIPE_UP_UNLOCK = 1
+            MetricsEvent.ACTION_LS_SHADE,  // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_FULL_SHADE = 2
+            MetricsEvent.ACTION_LS_HINT,  // SYSUI_LOCKSCREEN_GESTURE_TAP_UNLOCK_HINT = 3
+            MetricsEvent.ACTION_LS_CAMERA,  // SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA = 4
+            MetricsEvent.ACTION_LS_DIALER,  // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DIALER = 5
+            MetricsEvent.ACTION_LS_LOCK,  // SYSUI_LOCKSCREEN_GESTURE_TAP_LOCK = 6
+            MetricsEvent.ACTION_LS_NOTE,  // SYSUI_LOCKSCREEN_GESTURE_TAP_NOTIFICATION_ACTIVATE = 7
+            MetricsEvent.ACTION_LS_QS,  // SYSUI_LOCKSCREEN_GESTURE_SWIPE_DOWN_QS = 8
+            MetricsEvent.ACTION_SHADE_QS_PULL,  // SYSUI_SHADE_GESTURE_SWIPE_DOWN_QS = 9
+            MetricsEvent.ACTION_SHADE_QS_TAP  // SYSUI_TAP_TO_OPEN_QS = 10
+    };
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 1) {
+            try {
+                int type = ((Integer) operands[0]).intValue();
+                // ignore gesture length in operands[1]
+                // ignore gesture velocity in operands[2]
+
+                int category = MetricsEvent.VIEW_UNKNOWN;
+                if (type < GESTURE_TYPE_MAP.length) {
+                    category = GESTURE_TYPE_MAP[type];
+                }
+                if (category != MetricsEvent.VIEW_UNKNOWN) {
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(category);
+                    proto.setType(MetricsEvent.TYPE_ACTION);
+                    proto.setTimestamp(eventTimeMs);
+                    logger.addEvent(proto);
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationActionClickedParser.java b/core/java/com/android/internal/logging/legacy/NotificationActionClickedParser.java
new file mode 100644
index 0000000..67b84e9
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationActionClickedParser.java
@@ -0,0 +1,72 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification action button interaction event logs.
+ * @hide
+ */
+public class NotificationActionClickedParser extends TagParser {
+    private static final String TAG = "NotificationAction";
+    private static final int EVENTLOG_TAG = 27521;
+
+    private final NotificationKey mKey;
+
+    public NotificationActionClickedParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 1) {
+            try {
+                if (mKey.parse((String) operands[0])) {
+                    int index = (Integer) operands[1];
+                    parseTimes(operands, 2);
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(MetricsEvent.NOTIFICATION_ITEM_ACTION);
+                    proto.setType(MetricsEvent.TYPE_ACTION);
+                    proto.setSubtype(index);
+                    proto.setTimestamp(eventTimeMs);
+                    proto.setPackageName(mKey.mPackageName);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                    filltimes(proto);
+                    logger.addEvent(proto);
+                } else if (debug) {
+                    Log.e(TAG, "unable to parse key.");
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationAlertParser.java b/core/java/com/android/internal/logging/legacy/NotificationAlertParser.java
new file mode 100644
index 0000000..761197b
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationAlertParser.java
@@ -0,0 +1,86 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the new Android notification alert event logs.
+ * @hide
+ */
+public class NotificationAlertParser extends TagParser {
+    private static final String TAG = "NotificationAlertParser";
+    private static final int EVENTLOG_TAG = 27532;
+
+    @VisibleForTesting
+    static final int BUZZ = 0x00000001;
+    @VisibleForTesting
+    static final int BEEP = 0x00000002;
+    @VisibleForTesting
+    static final int BLINK = 0x00000004;
+
+    private final NotificationKey mKey;
+
+    public NotificationAlertParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 3) {
+            try {
+                final String keyString = (String) operands[0];
+                final boolean buzz = ((Integer) operands[1]) == 1;
+                final boolean beep = ((Integer) operands[2]) == 1;
+                final boolean blink = ((Integer) operands[3]) == 1;
+
+                if (mKey.parse(keyString)) {
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(MetricsEvent.NOTIFICATION_ALERT);
+                    proto.setType(MetricsEvent.TYPE_OPEN);
+                    proto.setSubtype((buzz ? BUZZ : 0) | (beep ? BEEP : 0) | (blink ? BLINK : 0));
+                    proto.setTimestamp(eventTimeMs);
+                    proto.setPackageName(mKey.mPackageName);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                    filltimes(proto);
+                    logger.addEvent(proto);
+                } else {
+                    if (debug) {
+                        Log.e(TAG, "unable to parse key: " + keyString);
+                    }
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+                return;
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationCanceledParser.java b/core/java/com/android/internal/logging/legacy/NotificationCanceledParser.java
new file mode 100644
index 0000000..0cab1a8
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationCanceledParser.java
@@ -0,0 +1,102 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification cancellation event logs.
+ * @hide
+ */
+public class NotificationCanceledParser extends TagParser {
+    private static final String TAG = "NotificationCanceled";
+    private static final int EVENTLOG_TAG = 27530;
+
+    // from com.android.server.notification.NotificationManagerService
+    static final int REASON_DELEGATE_CLICK = 1;
+    static final int REASON_DELEGATE_CANCEL = 2;
+    static final int REASON_DELEGATE_CANCEL_ALL = 3;
+    static final int REASON_PACKAGE_BANNED = 7;
+    static final int REASON_LISTENER_CANCEL = 10;
+    static final int REASON_LISTENER_CANCEL_ALL = 11;
+
+    private final NotificationKey mKey;
+
+    public NotificationCanceledParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 1) {
+            try {
+                final String keyString = (String) operands[0];
+                final int reason = (Integer) operands[1];
+                parseTimes(operands, 2);
+
+                // handle old style log
+                // TODO: delete once M is launched
+                if (operands.length < 5) {
+                    mSinceVisibleMillis = mSinceUpdateMillis;
+                    mSinceUpdateMillis = 0;
+                }
+
+                boolean intentional = true;
+                switch (reason) {
+                    case REASON_DELEGATE_CANCEL:
+                    case REASON_DELEGATE_CANCEL_ALL:
+                    case REASON_LISTENER_CANCEL:
+                    case REASON_LISTENER_CANCEL_ALL:
+                    case REASON_DELEGATE_CLICK:
+                    case REASON_PACKAGE_BANNED:
+                        break;
+                    default:
+                        intentional = false;
+                }
+
+                if (mKey.parse(keyString)) {
+                    if (intentional) {
+                        LogBuilder proto = logger.obtain();
+                        proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
+                        proto.setType(MetricsEvent.TYPE_DISMISS);
+                        proto.setSubtype(reason);
+                        proto.setTimestamp(eventTimeMs);
+                        proto.setPackageName(mKey.mPackageName);
+                        proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                        proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                        filltimes(proto);
+                        logger.addEvent(proto);
+                    }
+                } else if (debug) {
+                    Log.e(TAG, "unable to parse key: " + keyString);
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationClickedParser.java b/core/java/com/android/internal/logging/legacy/NotificationClickedParser.java
new file mode 100644
index 0000000..eeae0a8
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationClickedParser.java
@@ -0,0 +1,70 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification interaction event logs.
+ * @hide
+ */
+public class NotificationClickedParser extends TagParser {
+    private static final String TAG = "NotificationClicked";
+    private static final int EVENTLOG_TAG = 27520;
+
+    private final NotificationKey mKey;
+
+    public NotificationClickedParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 0) {
+            try {
+                if (mKey.parse((String) operands[0])) {
+                    parseTimes(operands, 1);
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
+                    proto.setType(MetricsEvent.TYPE_ACTION);
+                    proto.setTimestamp(eventTimeMs);
+                    proto.setPackageName(mKey.mPackageName);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                    filltimes(proto);
+                    logger.addEvent(proto);
+                } else if (debug) {
+                    Log.e(TAG, "unable to parse key.");
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationExpansionParser.java b/core/java/com/android/internal/logging/legacy/NotificationExpansionParser.java
new file mode 100644
index 0000000..d44b8b1
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationExpansionParser.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 com.android.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification expansion event logs.
+ * @hide
+ */
+public class NotificationExpansionParser extends TagParser {
+    private static final String TAG = "NotificationExpansion";
+    private static final int EVENTLOG_TAG = 27511;
+
+    private final NotificationKey mKey;
+
+    public NotificationExpansionParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 2) {
+            try {
+                if (mKey.parse((String) operands[0])) {
+                    boolean byUser = ((Integer) operands[1]) == 1;
+                    boolean expanded = ((Integer) operands[2]) == 1;
+                    parseTimes(operands, 3);
+
+                    if (!byUser || !expanded) {
+                        return;
+                    }
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
+                    proto.setType(MetricsEvent.TYPE_DETAIL);
+                    proto.setTimestamp(eventTimeMs);
+                    proto.setPackageName(mKey.mPackageName);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                    filltimes(proto);
+                    logger.addEvent(proto);
+                } else if (debug) {
+                    Log.e(TAG, "unable to parse key.");
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationKey.java b/core/java/com/android/internal/logging/legacy/NotificationKey.java
new file mode 100644
index 0000000..f8cac34
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationKey.java
@@ -0,0 +1,60 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+/**
+ * Parse Android notification keys
+ * @hide
+ */
+public class NotificationKey {
+
+    private static final String TAG = "NotificationKey";
+
+    public int mUser;
+    public String mPackageName;
+    public int mId;
+    public String mTag;
+    public int mUid;
+
+    public boolean parse(String key) {
+        if (key == null) {
+            return false;
+        }
+        boolean debug = Util.debug();
+        String[] parts = key.split("\\|");
+        if (parts.length == 5) {
+            try {
+                mUser = Integer.valueOf(parts[0]);
+                mPackageName = parts[1];
+                mId = Integer.valueOf(parts[2]);
+                mTag = parts[3].equals("null") ? "" : parts[3];
+                mUid = Integer.valueOf(parts[4]);
+                return true;
+            } catch (NumberFormatException e) {
+                if (debug) {
+                    Log.w(TAG, "could not parse notification key.", e);
+                }
+                return false;
+            }
+        }
+        if (debug) {
+            Log.w(TAG, "wrong number of parts in notification key: " + key);
+        }
+        return false;
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationPanelHiddenParser.java b/core/java/com/android/internal/logging/legacy/NotificationPanelHiddenParser.java
new file mode 100644
index 0000000..662295b
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationPanelHiddenParser.java
@@ -0,0 +1,42 @@
+/*
+ * 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.internal.logging.legacy;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification panel visibility event logs.
+ * @hide
+ */
+public class NotificationPanelHiddenParser extends TagParser {
+    private static final String TAG = "NotificationPanelHidden";
+    private static final int EVENTLOG_TAG = 27501;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        LogBuilder proto = logger.obtain();
+        proto.setCategory(MetricsEvent.NOTIFICATION_PANEL);
+        proto.setType(MetricsEvent.TYPE_CLOSE);
+        proto.setTimestamp(eventTimeMs);
+        logger.addEvent(proto);
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationPanelRevealedParser.java b/core/java/com/android/internal/logging/legacy/NotificationPanelRevealedParser.java
new file mode 100644
index 0000000..0566f0b
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationPanelRevealedParser.java
@@ -0,0 +1,56 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android notification panel visibility event logs.
+ * @hide
+ */
+public class NotificationPanelRevealedParser extends TagParser {
+    private static final String TAG = "NotificationPanelRevea";
+    private static final int EVENTLOG_TAG = 27500;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 1) {
+            try {
+                int load = ((Integer) operands[0]).intValue();
+                //logger.incrementBy(TronCounters.TRON_NOTIFICATION_LOAD, load);
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        }
+
+        LogBuilder proto = logger.obtain();
+        proto.setCategory(MetricsEvent.NOTIFICATION_PANEL);
+        proto.setType(MetricsEvent.TYPE_OPEN);
+        proto.setTimestamp(eventTimeMs);
+        logger.addEvent(proto);
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/NotificationVisibilityParser.java b/core/java/com/android/internal/logging/legacy/NotificationVisibilityParser.java
new file mode 100644
index 0000000..9185b91
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/NotificationVisibilityParser.java
@@ -0,0 +1,81 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the new Android notification visibility event logs.
+ * @hide
+ */
+public class NotificationVisibilityParser extends TagParser {
+    private static final String TAG = "NotificationVisibility";
+    private static final int EVENTLOG_TAG = 27531;
+
+    private final NotificationKey mKey;
+
+    public NotificationVisibilityParser() {
+        mKey = new NotificationKey();
+    }
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length > 1) {
+            try {
+                final String keyString = (String) operands[0];
+                final boolean visible = ((Integer) operands[1]) == 1;
+                parseTimes(operands, 2);
+                int index = 0;
+                if (operands.length > 5 && operands[5] instanceof Integer) {
+                    index = (Integer) operands[5];
+                }
+
+                if (mKey.parse(keyString)) {
+                    LogBuilder proto = logger.obtain();
+                    proto.setCategory(MetricsEvent.NOTIFICATION_ITEM);
+                    proto.setType(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
+                    proto.setTimestamp(eventTimeMs);
+                    proto.setPackageName(mKey.mPackageName);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_ID, mKey.mId);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_TAG, mKey.mTag);
+                    proto.addTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX, index);
+                    filltimes(proto);
+                    logger.addEvent(proto);
+                } else {
+                    if (debug) {
+                        Log.e(TAG, "unable to parse key: " + keyString);
+                    }
+                }
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+                return;
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/PowerScreenStateParser.java b/core/java/com/android/internal/logging/legacy/PowerScreenStateParser.java
new file mode 100644
index 0000000..3bf0f9d
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/PowerScreenStateParser.java
@@ -0,0 +1,66 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android lockscreen gesture logs.
+ * @hide
+ */
+public class PowerScreenStateParser extends TagParser {
+    private static final String TAG = "PowerScreenStateParser";
+    private static final int EVENTLOG_TAG = 2728;
+
+    // source of truth is android.view.WindowManagerPolicy, why:
+    // 0: on
+    // 1: OFF_BECAUSE_OF_ADMIN
+    // 2: OFF_BECAUSE_OF_USER
+    // 3: OFF_BECAUSE_OF_TIMEOUT
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 2) {
+            try {
+                // (offOrOn|1|5),(becauseOfUser|1|5),(totalTouchDownTime|2|3),(touchCycles|1|1)
+                boolean state = (((Integer) operands[0]).intValue()) == 1;
+                int why = ((Integer) operands[1]).intValue();
+
+                LogBuilder proto = logger.obtain();
+                proto.setCategory(MetricsEvent.SCREEN);
+                proto.setType(state ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
+                proto.setTimestamp(eventTimeMs);
+                proto.setSubtype(why);
+                logger.addEvent(proto);
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/StatusBarStateParser.java b/core/java/com/android/internal/logging/legacy/StatusBarStateParser.java
new file mode 100644
index 0000000..23abec4
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/StatusBarStateParser.java
@@ -0,0 +1,74 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android lockscreen gesture logs.
+ * @hide
+ */
+public class StatusBarStateParser extends TagParser {
+    private static final String TAG = "StatusBarStateParser";
+    private static final int EVENTLOG_TAG = 36004;
+
+    // source of truth is com.android.systemui.statusbar.StatusBarState
+    public static final int SHADE = 0;
+    public static final int KEYGUARD = 1;
+    public static final int SHADE_LOCKED = 2;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 6) {
+            try {
+                // [state, isShowing, isOccluded, isBouncerShowing, isSecure, isCurrentlyInsecure]
+                int state = ((Integer) operands[0]).intValue();
+                boolean isBouncerShowing = (((Integer) operands[3]).intValue()) == 1;
+                int isSecure = ((Integer) operands[4]).intValue();
+
+                int view = MetricsEvent.LOCKSCREEN;
+                int type = MetricsEvent.TYPE_OPEN;
+                if (state == SHADE) {
+                    type = MetricsEvent.TYPE_CLOSE;
+                } else if (isBouncerShowing) {
+                    view = MetricsEvent.BOUNCER;
+                }
+
+                LogBuilder proto = logger.obtain();
+                proto.setCategory(view);
+                proto.setType(type);
+                proto.setTimestamp(eventTimeMs);
+                proto.setSubtype(isSecure);
+                logger.addEvent(proto);
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiActionParser.java b/core/java/com/android/internal/logging/legacy/SysuiActionParser.java
new file mode 100644
index 0000000..7f91f92
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/SysuiActionParser.java
@@ -0,0 +1,81 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android framework sysui action logs.
+ * @hide
+ */
+public class SysuiActionParser extends TagParser {
+    private static final String TAG = "SysuiActionParser";
+    private static final int EVENTLOG_TAG = 524288;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        try {
+            String packageName = null;
+            int subType = -1;
+            boolean hasSubType = false;
+            if (operands.length > 1) {
+                String arg = (String) operands[1];
+                if (arg.equals("true")) {
+                    hasSubType = true;
+                    subType = 1;
+                } else if (arg.equals("false")) {
+                    hasSubType = true;
+                    subType = 0;
+                } else if (arg.matches("^-?\\d+$")) {
+                    try {
+                        subType = Integer.valueOf(arg);
+                        hasSubType = true;
+                    } catch (NumberFormatException e) {
+                    }
+                } else {
+                    packageName = arg;
+                }
+            }
+            if (operands.length > 0) {
+                int category = ((Integer) operands[0]).intValue();
+                LogBuilder proto = logger.obtain();
+                proto.setCategory(category);
+                proto.setType(MetricsEvent.TYPE_ACTION);
+                proto.setTimestamp(eventTimeMs);
+                if (packageName != null) {
+                    proto.setPackageName(packageName);
+                }
+                if (hasSubType) {
+                    proto.setSubtype(subType);
+                }
+                logger.addEvent(proto);
+            }
+        } catch (ClassCastException e) {
+            if (debug) {
+                Log.e(TAG, "unexpected operand type: ", e);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiMultiActionParser.java b/core/java/com/android/internal/logging/legacy/SysuiMultiActionParser.java
new file mode 100644
index 0000000..f9b2f49
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/SysuiMultiActionParser.java
@@ -0,0 +1,49 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * ...and one parser to rule them all.
+ *
+ * This should, at some point in the future, be the only parser.
+ * @hide
+ */
+public class SysuiMultiActionParser extends TagParser {
+    private static final String TAG = "SysuiMultiActionParser";
+    private static final int EVENTLOG_TAG = 524292;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        try {
+            logger.addEvent(new LogBuilder(operands).setTimestamp(eventTimeMs));
+        } catch (ClassCastException e) {
+            if (debug) {
+                Log.e(TAG, "unexpected operand type: ", e);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiQueryParser.java b/core/java/com/android/internal/logging/legacy/SysuiQueryParser.java
new file mode 100644
index 0000000..7b3c0a7
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/SysuiQueryParser.java
@@ -0,0 +1,32 @@
+/*
+ * 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.internal.logging.legacy;
+
+/**
+ * Parse the Android framework sysui search query logs.
+ * For now just treat them like actions.
+ * @hide
+ */
+public class SysuiQueryParser extends SysuiActionParser {
+    private static final String TAG = "SysuiQueryParser";
+
+    private static final int EVENTLOG_TAG = 524289;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/SysuiViewVisibilityParser.java b/core/java/com/android/internal/logging/legacy/SysuiViewVisibilityParser.java
new file mode 100644
index 0000000..5d5aec0
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/SysuiViewVisibilityParser.java
@@ -0,0 +1,58 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Parse the Android framework sysui view visibility logs.
+ * @hide
+ */
+public class SysuiViewVisibilityParser extends TagParser {
+    private static final String TAG = "SysuiViewVisibility";
+    private static final int EVENTLOG_TAG = 524287;
+
+    @Override
+    public int getTag() {
+        return EVENTLOG_TAG;
+    }
+
+    @Override
+    public void parseEvent(TronLogger logger, long eventTimeMs, Object[] operands) {
+        final boolean debug = Util.debug();
+        if (operands.length >= 2) {
+            try {
+                int category = ((Integer) operands[0]).intValue();
+                boolean visibility = ((Integer) operands[1]).intValue() != 0;
+
+                LogBuilder proto = logger.obtain();
+                proto.setCategory(category);
+                proto.setType(visibility ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE);
+                proto.setTimestamp(eventTimeMs);
+                logger.addEvent(proto);
+            } catch (ClassCastException e) {
+                if (debug) {
+                    Log.e(TAG, "unexpected operand type: ", e);
+                }
+            }
+        } else if (debug) {
+            Log.w(TAG, "wrong number of operands: " + operands.length);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/TagParser.java b/core/java/com/android/internal/logging/legacy/TagParser.java
new file mode 100755
index 0000000..c62d084
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/TagParser.java
@@ -0,0 +1,104 @@
+/*
+ * 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.internal.logging.legacy;
+
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+/**
+ * Abstraction layer between EventLog static classes and the actual TagParsers.
+ * @hide
+ */
+public abstract class TagParser {
+    private static final String TAG = "TagParser";
+
+    protected int mSinceCreationMillis;
+    protected int mSinceUpdateMillis;
+    protected int mSinceVisibleMillis;
+
+    abstract int getTag();
+
+    @VisibleForTesting
+    abstract public void parseEvent(TronLogger logger, long eventTimeMs, Object[] objects);
+
+    /**
+     * Parse the event into the proto: return true if proto was modified.
+     */
+    public void  parseEvent(TronLogger logger, EventLogCollector.Event event) {
+        final boolean debug = Util.debug();
+        Object data = event.getData();
+        Object[] objects;
+        if (data instanceof Object[]) {
+            objects = (Object[]) data;
+            for (int i = 0; i < objects.length; i++) {
+                if (objects[i] == null) {
+                    if (debug) {
+                        Log.d(TAG, "unexpected null value:" + event.getTag());
+                    }
+                    return;
+                }
+            }
+        } else {
+            // wrap scalar objects
+            objects = new Object[1];
+            objects[0] = data;
+        }
+
+        parseEvent(logger, event.getTimeNanos() / 1000000, objects);
+    }
+
+    protected void resetTimes() {
+        mSinceCreationMillis = 0;
+        mSinceUpdateMillis = 0;
+        mSinceVisibleMillis = 0;
+    }
+
+    public void parseTimes(Object[] operands, int index) {
+        resetTimes();
+
+        if (operands.length > index && operands[index] instanceof Integer) {
+            mSinceCreationMillis = (Integer) operands[index];
+        }
+
+        index++;
+        if (operands.length > index && operands[index] instanceof Integer) {
+            mSinceUpdateMillis = (Integer) operands[index];
+        }
+
+        index++;
+        if (operands.length > index && operands[index] instanceof Integer) {
+            mSinceVisibleMillis = (Integer) operands[index];
+        }
+    }
+
+   public void filltimes(LogBuilder proto) {
+        if (mSinceCreationMillis != 0) {
+            proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS,
+                    mSinceCreationMillis);
+        }
+        if (mSinceUpdateMillis != 0) {
+            proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS,
+                    mSinceUpdateMillis);
+        }
+        if (mSinceVisibleMillis != 0) {
+            proto.addTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS,
+                    mSinceVisibleMillis);
+        }
+    }
+}
diff --git a/core/java/com/android/internal/logging/legacy/TronCounters.java b/core/java/com/android/internal/logging/legacy/TronCounters.java
new file mode 100644
index 0000000..e0828a2
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/TronCounters.java
@@ -0,0 +1,72 @@
+/*
+ * 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.internal.logging.legacy;
+
+/**
+ * Names of the counters that the Tron package defines.
+ *
+ * Other counter names may be generated by AOSP code.
+ * @hide
+ */
+public class TronCounters {
+
+    static final String TRON_COLLECTIONS = "tron_collections";
+
+    static final String TRON_COLLECTION_PERIOD = "tron_collection_period_minutes";
+
+    static final String TRON_EVENTLOG_LENGTH = "tron_eventlog_horizon";
+
+    static final String TRON_NOTE_DISMISS = "tron_note_dismiss";
+
+    static final String TRON_NOTE_DISMISS_BY_USER = "tron_note_dismiss_user";
+
+    static final String TRON_NOTE_DISMISS_BY_CLICK = "tron_note_dismiss_click";
+
+    static final String TRON_NOTE_DISMISS_BY_LISTENER = "tron_note_dismiss_listener";
+
+    static final String TRON_NOTE_DISMISS_BY_BAN = "tron_note_dismiss_ban";
+
+    static final String TRON_NOTE_REVEALED = "tron_note_revealed";
+
+    static final String TRON_NOTIFICATION_LOAD = "tron_notification_load";
+
+    static final String TRON_VIEW = "tron_view";
+
+    static final String TRON_ACTION = "tron_action";
+
+    static final String TRON_DETAIL = "tron_detail";
+
+    static final String TRON_NOTE_LIFETIME = "tron_note_lifetime";
+
+    /** Append the AOSP-generated name */
+    static final String TRON_AOSP_PREFIX = "tron_varz_";
+
+    static final String TRON_ACTION_BAD_INT = "tron_action_bad_int";
+
+    static final String TRON_NOTE_FRESHNESS = "tron_note_freshness";
+
+    static final String TRON_NOTE_BUZZ = "tron_note_buzz";
+
+    static final String TRON_NOTE_BEEP = "tron_note_beep";
+
+    static final String TRON_NOTE_BLINK = "tron_note_blink";
+
+    static final String TRON_DISABLE = "tron_disable";
+
+    static final String TRON_LAST_HEART_AGE = "tron_last_heart_minutes";
+
+    static final String TRON_HEARTS_SEEN = "tron_hearts_seen";
+}
diff --git a/core/java/com/android/internal/logging/legacy/TronLogger.java b/core/java/com/android/internal/logging/legacy/TronLogger.java
new file mode 100644
index 0000000..dabe314
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/TronLogger.java
@@ -0,0 +1,49 @@
+/*
+ * 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.internal.logging.legacy;
+
+import com.android.internal.logging.LogBuilder;
+
+/**
+ * An entity that knows how to log events and counters.
+ */
+public interface TronLogger {
+    /** Add one to the named counter. */
+    void increment(String counterName);
+
+    /** Add an arbitrary value to the named counter. */
+    void incrementBy(String counterName, int value);
+
+    /** Increment a specified bucket on the named histogram by one. */
+    void incrementIntHistogram(String counterName, int bucket);
+
+    /** Increment the specified bucket on the named histogram by one. */
+    void incrementLongHistogram(String counterName, long bucket);
+
+    /** Obtain a SystemUiEvent proto, must release this with dispose() or addEvent(). */
+    LogBuilder obtain();
+
+    void dispose(LogBuilder proto);
+
+    /** Submit an event to be logged. Logger will dispose of proto. */
+    void addEvent(LogBuilder proto);
+
+    /** Get a config flag. */
+    boolean getConfig(String configName);
+
+    /** Set a config flag. */
+    void setConfig(String configName, boolean newValue);
+}
diff --git a/core/java/com/android/internal/logging/legacy/Util.java b/core/java/com/android/internal/logging/legacy/Util.java
new file mode 100644
index 0000000..99f71ca
--- /dev/null
+++ b/core/java/com/android/internal/logging/legacy/Util.java
@@ -0,0 +1,25 @@
+/*
+ * 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.internal.logging.legacy;
+
+/**
+ * Created by cwren on 11/21/16.
+ */
+public class Util {
+    public static boolean debug() {
+        return false;
+    }
+}
diff --git a/core/java/com/android/internal/os/AppFuseMount.aidl b/core/java/com/android/internal/os/AppFuseMount.aidl
new file mode 100644
index 0000000..66cf95b
--- /dev/null
+++ b/core/java/com/android/internal/os/AppFuseMount.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+parcelable AppFuseMount;
diff --git a/core/java/com/android/internal/os/AppFuseMount.java b/core/java/com/android/internal/os/AppFuseMount.java
index b392186..04d7211 100644
--- a/core/java/com/android/internal/os/AppFuseMount.java
+++ b/core/java/com/android/internal/os/AppFuseMount.java
@@ -19,14 +19,26 @@
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
-import java.io.File;
+import android.os.storage.IStorageManager;
+import com.android.internal.util.Preconditions;
 
+/**
+ * Parcelable class representing AppFuse mount.
+ * This conveys the result for IStorageManager#openProxyFileDescriptor.
+ * @see IStorageManager#openProxyFileDescriptor
+ */
 public class AppFuseMount implements Parcelable {
-    final public File mountPoint;
+    final public int mountPointId;
     final public ParcelFileDescriptor fd;
 
-    public AppFuseMount(File mountPoint, ParcelFileDescriptor fd) {
-        this.mountPoint = mountPoint;
+    /**
+     * @param mountPointId Integer number for mount point that is unique in the lifetime of
+     *     StorageManagerService.
+     * @param fd File descriptor pointing /dev/fuse and tagged with the mount point.
+     */
+    public AppFuseMount(int mountPointId, ParcelFileDescriptor fd) {
+        Preconditions.checkNotNull(fd);
+        this.mountPointId = mountPointId;
         this.fd = fd;
     }
 
@@ -37,7 +49,7 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(this.mountPoint.getPath());
+        dest.writeInt(this.mountPointId);
         dest.writeParcelable(fd, flags);
     }
 
@@ -45,7 +57,7 @@
             new Parcelable.Creator<AppFuseMount>() {
         @Override
         public AppFuseMount createFromParcel(Parcel in) {
-            return new AppFuseMount(new File(in.readString()), in.readParcelable(null));
+            return new AppFuseMount(in.readInt(), in.readParcelable(null));
         }
 
         @Override
diff --git a/core/java/com/android/internal/os/FuseAppLoop.java b/core/java/com/android/internal/os/FuseAppLoop.java
index 34253ce..3603b6d 100644
--- a/core/java/com/android/internal/os/FuseAppLoop.java
+++ b/core/java/com/android/internal/os/FuseAppLoop.java
@@ -18,34 +18,38 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.os.IProxyFileDescriptorCallback;
+import android.os.ProxyFileDescriptorCallback;
 import android.os.ParcelFileDescriptor;
 import android.system.ErrnoException;
 import android.system.OsConstants;
 import android.util.Log;
 import android.util.SparseArray;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
-import java.io.File;
-import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.util.concurrent.ThreadFactory;
 
 public class FuseAppLoop {
     private static final String TAG = "FuseAppLoop";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     public static final int ROOT_INODE = 1;
     private static final int MIN_INODE = 2;
+    private static final ThreadFactory sDefaultThreadFactory = new ThreadFactory() {
+        @Override
+        public Thread newThread(Runnable r) {
+            return new Thread(r, TAG);
+        }
+    };
 
     private final Object mLock = new Object();
-    private final File mParent;
+    private final int mMountPointId;
+    private final Thread mThread;
 
     @GuardedBy("mLock")
     private final SparseArray<CallbackEntry> mCallbackMap = new SparseArray<>();
 
-    @GuardedBy("mLock")
-    private boolean mActive = true;
-
     /**
      * Sequential number can be used as file name and inode in AppFuse.
      * 0 is regarded as an error, 1 is mount point. So we start the number from 2.
@@ -53,35 +57,40 @@
     @GuardedBy("mLock")
     private int mNextInode = MIN_INODE;
 
-    private FuseAppLoop(@NonNull File parent) {
-        mParent = parent;
-    }
-
-    public static @NonNull FuseAppLoop open(
-            @NonNull File parent, @NonNull ParcelFileDescriptor fd) {
-        Preconditions.checkNotNull(parent);
-        Preconditions.checkNotNull(fd);
-        final FuseAppLoop bridge = new FuseAppLoop(parent);
+    private FuseAppLoop(
+            int mountPointId, @NonNull ParcelFileDescriptor fd, @Nullable ThreadFactory factory) {
+        mMountPointId = mountPointId;
         final int rawFd = fd.detachFd();
-        new Thread(new Runnable() {
+        if (factory == null) {
+            factory = sDefaultThreadFactory;
+        }
+        mThread = factory.newThread(new Runnable() {
             @Override
             public void run() {
-                bridge.native_start_loop(rawFd);
+                // rawFd is closed by native_start_loop. Java code does not need to close it.
+                native_start_loop(rawFd);
             }
-        }, TAG).start();
-        return bridge;
+        });
     }
 
-    public @NonNull ParcelFileDescriptor openFile(int mode, IProxyFileDescriptorCallback callback)
+    public static @NonNull FuseAppLoop open(int mountPointId, @NonNull ParcelFileDescriptor fd,
+            @Nullable ThreadFactory factory) {
+        Preconditions.checkNotNull(fd);
+        final FuseAppLoop loop = new FuseAppLoop(mountPointId, fd, factory);
+        loop.mThread.start();
+        return loop;
+    }
+
+    public int registerCallback(@NonNull ProxyFileDescriptorCallback callback)
             throws UnmountedException, IOException {
-        int id;
+        if (mThread.getState() == Thread.State.TERMINATED) {
+            throw new UnmountedException();
+        }
         synchronized (mLock) {
-            if (!mActive) {
-                throw new UnmountedException();
-            }
             if (mCallbackMap.size() >= Integer.MAX_VALUE - MIN_INODE) {
                 throw new IOException("Too many opened files.");
             }
+            int id;
             while (true) {
                 id = mNextInode;
                 mNextInode++;
@@ -92,24 +101,17 @@
                     break;
                 }
             }
-
-            // Register callback after we succeed to create pfd.
             mCallbackMap.put(id, new CallbackEntry(callback));
-        }
-        try {
-            return ParcelFileDescriptor.open(new File(mParent, String.valueOf(id)), mode);
-        } catch (FileNotFoundException error) {
-            synchronized (mLock) {
-                mCallbackMap.remove(id);
-            }
-            throw error;
+            return id;
         }
     }
 
-    public @Nullable File getMountPoint() {
-        synchronized (mLock) {
-            return mActive ? mParent : null;
-        }
+    public void unregisterCallback(int id) {
+        mCallbackMap.remove(id);
+    }
+
+    public int getMountPointId() {
+        return mMountPointId;
     }
 
     private CallbackEntry getCallbackEntryOrThrowLocked(long inode) throws ErrnoException {
@@ -128,7 +130,7 @@
             try {
                 return getCallbackEntryOrThrowLocked(inode).callback.onGetSize();
             } catch (ErrnoException exp) {
-                return -exp.errno;
+                return getError(exp);
             }
         }
     }
@@ -147,7 +149,7 @@
                 // file twice.
                 return (int) inode;
             } catch (ErrnoException exp) {
-                return -exp.errno;
+                return getError(exp);
             }
         }
     }
@@ -160,7 +162,7 @@
                 getCallbackEntryOrThrowLocked(inode).callback.onFsync();
                 return 0;
             } catch (ErrnoException exp) {
-                return -exp.errno;
+                return getError(exp);
             }
         }
     }
@@ -169,12 +171,14 @@
     @SuppressWarnings("unused")
     private int onRelease(long inode) {
         synchronized(mLock) {
-            mCallbackMap.remove(checkInode(inode));
-            if (mCallbackMap.size() == 0) {
-                mActive = false;
-                return -1;
+            try {
+                getCallbackEntryOrThrowLocked(inode).callback.onRelease();
+                return 0;
+            } catch (ErrnoException exp) {
+                return getError(exp);
+            } finally {
+                mCallbackMap.remove(checkInode(inode));
             }
-            return 0;
         }
     }
 
@@ -185,7 +189,7 @@
             try {
                 return getCallbackEntryOrThrowLocked(inode).callback.onRead(offset, size, bytes);
             } catch (ErrnoException exp) {
-                return -exp.errno;
+                return getError(exp);
             }
         }
     }
@@ -197,11 +201,17 @@
             try {
                 return getCallbackEntryOrThrowLocked(inode).callback.onWrite(offset, size, bytes);
             } catch (ErrnoException exp) {
-                return -exp.errno;
+                return getError(exp);
             }
         }
     }
 
+    private static int getError(@NonNull ErrnoException exp) {
+        // Should not return ENOSYS because the kernel stops
+        // dispatching the FUSE action once FUSE implementation returns ENOSYS for the action.
+        return exp.errno != OsConstants.ENOSYS ? -exp.errno : -OsConstants.EIO;
+    }
+
     native boolean native_start_loop(int fd);
 
     private static int checkInode(long inode) {
@@ -212,9 +222,9 @@
     public static class UnmountedException extends Exception {}
 
     private static class CallbackEntry {
-        final IProxyFileDescriptorCallback callback;
+        final ProxyFileDescriptorCallback callback;
         boolean opened;
-        CallbackEntry(IProxyFileDescriptorCallback callback) {
+        CallbackEntry(ProxyFileDescriptorCallback callback) {
             Preconditions.checkNotNull(callback);
             this.callback = callback;
         }
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index b368437..8eb75c0 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -80,6 +80,7 @@
 public class ZygoteInit {
     private static final String TAG = "Zygote";
 
+    private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
     private static final String PROPERTY_RUNNING_IN_CONTAINER = "ro.boot.container";
 
     private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
@@ -124,6 +125,9 @@
         bootTimingsTraceLog.traceBegin("PreloadResources");
         preloadResources();
         bootTimingsTraceLog.traceEnd(); // PreloadResources
+        bootTimingsTraceLog.traceBegin("PreloadOpenGL");
+        preloadOpenGL();
+        bootTimingsTraceLog.traceEnd(); // PreloadOpenGL
         preloadSharedLibraries();
         preloadTextResources();
         // Ask the WebViewFactory to do any initialization that must run in the zygote process,
@@ -173,6 +177,12 @@
         System.loadLibrary("jnigraphics");
     }
 
+    private static void preloadOpenGL() {
+        if (!SystemProperties.getBoolean(PROPERTY_DISABLE_OPENGL_PRELOADING, false)) {
+            EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
+        }
+    }
+
     private static void preloadTextResources() {
         Hyphenator.init();
         TextView.preloadFontCache();
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index 7ee5170..087383d 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -306,6 +306,10 @@
         return ColorUtilsFromCompat.LABToColor(high, a, b);
     }
 
+    public static int ensureTextContrastOnBlack(int color) {
+        return findContrastColorAgainstDark(color, Color.BLACK, true /* fg */, 12);
+    }
+
     /**
      * Finds a text color with sufficient contrast over bg that has the same hue as the original
      * color, assuming it is for large text.
@@ -393,6 +397,25 @@
         return ColorUtilsFromCompat.LABToColor(result[0], result[1], result[2]);
     }
 
+    public static int resolveAmbientColor(Context context, int notificationColor) {
+        final int resolvedColor = resolveColor(context, notificationColor);
+
+        int color = resolvedColor;
+        color = NotificationColorUtil.ensureTextContrastOnBlack(color);
+
+        if (color != resolvedColor) {
+            if (DEBUG){
+                Log.w(TAG, String.format(
+                        "Ambient contrast of notification for %s is %s (over black)"
+                                + " by changing #%s to #%s",
+                        context.getPackageName(),
+                        NotificationColorUtil.contrastChange(resolvedColor, color, Color.BLACK),
+                        Integer.toHexString(resolvedColor), Integer.toHexString(color)));
+            }
+        }
+        return color;
+    }
+
     /**
      * Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
      */
diff --git a/core/java/com/android/internal/widget/CachingIconView.java b/core/java/com/android/internal/widget/CachingIconView.java
index 20230cd..b172dbc 100644
--- a/core/java/com/android/internal/widget/CachingIconView.java
+++ b/core/java/com/android/internal/widget/CachingIconView.java
@@ -187,6 +187,7 @@
     }
 
     @Override
+    @RemotableViewMethod
     public void setVisibility(int visibility) {
         mDesiredVisibility = visibility;
         updateVisibility();
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 68034f6..6a9ed8e 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -238,6 +238,7 @@
     libnativehelper \
     liblog \
     libcutils \
+    libdebuggerd_client \
     libutils \
     libbinder \
     libui \
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 6f97c60..d5f33cf 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -8,7 +8,6 @@
 #include "GraphicsJNI.h"
 
 #include "SkCanvas.h"
-#include "SkDevice.h"
 #include "SkMath.h"
 #include "SkRegion.h"
 #include <android_runtime/AndroidRuntime.h>
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 508c9ff..e899db5 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -5,7 +5,6 @@
 #include "SkBitmap.h"
 #include "SkBRDAllocator.h"
 #include "SkCodec.h"
-#include "SkDevice.h"
 #include "SkPixelRef.h"
 #include "SkMallocPixelRef.h"
 #include "SkPoint.h"
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index 14d7e81..be3a87b 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -33,7 +33,7 @@
 #include <string>
 
 #include <android-base/stringprintf.h>
-#include <cutils/debugger.h>
+#include <debuggerd/client.h>
 #include <log/log.h>
 #include <utils/misc.h>
 #include <utils/String8.h>
diff --git a/core/jni/android_view_PointerIcon.cpp b/core/jni/android_view_PointerIcon.cpp
index 6b634df..4150636 100644
--- a/core/jni/android_view_PointerIcon.cpp
+++ b/core/jni/android_view_PointerIcon.cpp
@@ -78,6 +78,9 @@
 
 status_t android_view_PointerIcon_getLoadedIcon(JNIEnv* env, jobject pointerIconObj,
         PointerIcon* outPointerIcon) {
+    if (!pointerIconObj) {
+        return BAD_VALUE;
+    }
     outPointerIcon->style = env->GetIntField(pointerIconObj, gPointerIconClassInfo.mType);
     outPointerIcon->hotSpotX = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotX);
     outPointerIcon->hotSpotY = env->GetFloatField(pointerIconObj, gPointerIconClassInfo.mHotSpotY);
diff --git a/core/jni/com_android_internal_os_FuseAppLoop.cpp b/core/jni/com_android_internal_os_FuseAppLoop.cpp
index 92a6934..dd003eb 100644
--- a/core/jni/com_android_internal_os_FuseAppLoop.cpp
+++ b/core/jni/com_android_internal_os_FuseAppLoop.cpp
@@ -51,7 +51,6 @@
     JNIEnv* const mEnv;
     jobject const mSelf;
     ScopedLocalRef<jbyteArray> mJniBuffer;
-    bool mActive;
 
     template <typename T>
     T checkException(T result) const {
@@ -67,8 +66,7 @@
     Callback(JNIEnv* env, jobject self) :
         mEnv(env),
         mSelf(self),
-        mJniBuffer(env, nullptr),
-        mActive(true) {}
+        mJniBuffer(env, nullptr) {}
 
     bool Init() {
         mJniBuffer.reset(mEnv->NewByteArray(kBufferSize));
@@ -76,7 +74,7 @@
     }
 
     bool IsActive() override {
-        return mActive;
+        return true;
     }
 
     int64_t OnGetSize(uint64_t inode) override {
@@ -92,10 +90,7 @@
     }
 
     int32_t OnRelease(uint64_t inode) override {
-        if (checkException(mEnv->CallIntMethod(mSelf, gOnReleaseMethod, inode)) == -1) {
-            mActive = false;
-        }
-        return fuse::kFuseSuccess;
+        return checkException(mEnv->CallIntMethod(mSelf, gOnReleaseMethod, inode));
     }
 
     int32_t OnRead(uint64_t inode, uint64_t offset, uint32_t size, void* buffer) override {
diff --git a/core/proto/android/os/incident.proto b/core/proto/android/os/incident.proto
index ec2f32b..c3b0ff1 100644
--- a/core/proto/android/os/incident.proto
+++ b/core/proto/android/os/incident.proto
@@ -21,6 +21,7 @@
 
 import "frameworks/base/libs/incident/proto/android/privacy.proto";
 import "frameworks/base/core/proto/android/service/fingerprint.proto";
+import "frameworks/base/core/proto/android/service/netstats.proto";
 
 package android.os;
 
@@ -49,4 +50,5 @@
 
     // System Services
     android.service.fingerprint.FingerprintServiceDumpProto fingerprint = 3000;
+    android.service.NetworkStatsServiceDumpProto netstats = 3001;
 }
diff --git a/core/proto/android/service/netstats.proto b/core/proto/android/service/netstats.proto
new file mode 100644
index 0000000..5cca6ab
--- /dev/null
+++ b/core/proto/android/service/netstats.proto
@@ -0,0 +1,117 @@
+/*
+ * 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.
+ */
+
+syntax = "proto3";
+
+package android.service;
+
+option java_multiple_files = true;
+option java_outer_classname = "NetworkStatsServiceProto";
+
+// Represents dumpsys from NetworkStatsService (netstats).
+message NetworkStatsServiceDumpProto {
+    repeated NetworkInterfaceProto active_interfaces = 1;
+
+    repeated NetworkInterfaceProto active_uid_interfaces = 2;
+
+    NetworkStatsRecorderProto dev_stats = 3;
+
+    NetworkStatsRecorderProto xt_stats = 4;
+
+    NetworkStatsRecorderProto uid_stats = 5;
+
+    NetworkStatsRecorderProto uid_tag_stats = 6;
+}
+
+// Corresponds to NetworkStatsService.mActiveIfaces/mActiveUidIfaces.
+message NetworkInterfaceProto {
+    string interface = 1;
+
+    NetworkIdentitySetProto identities = 2;
+}
+
+// Corresponds to NetworkIdentitySet.
+message NetworkIdentitySetProto {
+    repeated NetworkIdentityProto identities = 1;
+}
+
+// Corresponds to NetworkIdentity.
+message NetworkIdentityProto {
+    // Constats from ConnectivityManager.TYPE_*.
+    int32 type = 1;
+
+    string subscriber_id = 2;
+
+    string network_id = 3;
+
+    bool roaming = 4;
+
+    bool metered = 5;
+}
+
+// Corresponds to NetworkStatsRecorder.
+message NetworkStatsRecorderProto {
+    int64 pending_total_bytes = 1;
+
+    NetworkStatsCollectionProto complete_history = 2;
+}
+
+// Corresponds to NetworkStatsCollection.
+message NetworkStatsCollectionProto {
+    repeated NetworkStatsCollectionStatsProto stats = 1;
+}
+
+// Corresponds to NetworkStatsCollection.mStats.
+message NetworkStatsCollectionStatsProto {
+    NetworkStatsCollectionKeyProto key = 1;
+
+    NetworkStatsHistoryProto history = 2;
+}
+
+// Corresponds to NetworkStatsCollection.Key.
+message NetworkStatsCollectionKeyProto {
+    NetworkIdentitySetProto identity = 1;
+
+    int32 uid = 2;
+
+    int32 set = 3;
+
+    int32 tag = 4;
+}
+
+// Corresponds to NetworkStatsHistory.
+message NetworkStatsHistoryProto {
+    // Duration for this bucket in milliseconds.
+    int64 bucket_duration_ms = 1;
+
+    repeated NetworkStatsHistoryBucketProto buckets = 2;
+}
+
+// Corresponds to each bucket in NetworkStatsHistory.
+message NetworkStatsHistoryBucketProto {
+    // Bucket start time in milliseconds since epoch.
+    int64 bucket_start_ms = 1;
+
+    int64 rx_bytes = 2;
+
+    int64 rx_packets = 3;
+
+    int64 tx_bytes = 4;
+
+    int64 tx_packets = 5;
+
+    int64 operations = 6;
+}
diff --git a/core/res/res/color/text_color_primary.xml b/core/res/res/color/text_color_primary.xml
new file mode 100644
index 0000000..831a9c4
--- /dev/null
+++ b/core/res/res/color/text_color_primary.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_enabled="false"
+        android:alpha="?attr/disabledAlpha"
+        android:color="?attr/colorForeground"/>
+    <item android:alpha="?attr/primaryContentAlpha"
+        android:color="?attr/colorForeground"/>
+</selector>
diff --git a/core/res/res/layout/notification_template_material_ambient.xml b/core/res/res/layout/notification_template_material_ambient.xml
new file mode 100644
index 0000000..1ae317c
--- /dev/null
+++ b/core/res/res/layout/notification_template_material_ambient.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/status_bar_latest_event_content"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:tag="ambient"
+    >
+    <include layout="@layout/notification_template_header" />
+
+    <LinearLayout
+            android:id="@+id/notification_action_list_margin_target"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:layout_gravity="top"
+            android:layout_marginTop="@dimen/notification_content_margin_top"
+            android:layout_marginBottom="@dimen/notification_action_list_height"
+            android:clipToPadding="false"
+            android:orientation="vertical">
+
+        <LinearLayout
+            android:id="@+id/notification_main_column"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:layout_gravity="top"
+            android:paddingStart="@dimen/notification_content_margin_start"
+            android:paddingEnd="@dimen/notification_content_margin_end"
+            android:clipToPadding="false"
+            android:minHeight="@dimen/notification_min_content_height"
+            android:orientation="vertical"
+            >
+            <TextView android:id="@+id/title"
+                android:textAppearance="@style/TextAppearance.Material.Notification.Title"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:singleLine="true"
+                android:ellipsize="marquee"
+                android:fadingEdge="horizontal"
+                android:textSize="20sp"
+                android:textColor="@android:color/white"
+            />
+            <TextView android:id="@+id/text"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:paddingBottom="@dimen/notification_content_margin_bottom"
+                android:textAppearance="@style/TextAppearance.Material.Notification"
+                android:singleLine="false"
+                android:layout_weight="1"
+                android:gravity="top"
+                android:visibility="gone"
+                android:textSize="18sp"
+                android:textColor="@android:color/white"
+                android:layout_marginTop="4dp"
+            />
+        </LinearLayout>
+    </LinearLayout>
+    <include layout="@layout/notification_material_action_list" />
+</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index cc64bb3..c004243 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Het <xliff:g id="LABEL">%1$s</xliff:g> gedeaktiveer"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferensie-oproep"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Nutswenk"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 953d3da..24feab7 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1551,7 +1551,7 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2ኛ ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3ኛ ስራ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
-    <string name="lock_to_app_toast" msgid="7693684144593484">"ይህን ማያ ገጽ ለመንቀል ተመለስ እና አጠቃላ እይታን ተጭነው ይያዙ።"</string>
+    <string name="lock_to_app_toast" msgid="7693684144593484">"ይህን ማያ ገጽ ለመንቀል ተመለስ እና አጠቃላይ እይታን ተጭነው ይያዙ።"</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"መተግበሪያ ተሰክቷል፦ በዚህ መሣሪያ ላይ ማላቀቅ አይፈቀድም።"</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"ማያ ገጽ ተሰክቷል"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"ማያ ገጽ ተነቅሏል"</string>
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ተሰናክሏል"</string>
     <string name="conference_call" msgid="3751093130790472426">"የስብሰባ ጥሪ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"የመሣሪያ ጥቆማ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 1a8dc8e..f28d044 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1795,4 +1795,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"تم تعطيل <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"مكالمة جماعية"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"تلميح"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 36377e6..9b55a55 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiv edildi"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konfrans Zəngi"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 80d81fc..b0c62e9 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1702,4 +1702,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Vidžet <xliff:g id="LABEL">%1$s</xliff:g> je onemogućen"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Objašnjenje"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index e5f42c4..50cfa82 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Адключаны <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Канферэнц-выклік"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Падказка"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 05b8412..4b39129 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g>: Деактивирано"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конферентно обаждане"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Подсказка"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index dbe7938..b6f7a12 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"অক্ষম করা <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"কনফারেন্স কল"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"টুলটিপ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index c4a3b8f..71c9f7d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1704,4 +1704,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Onemogućen <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Savjet za alat"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 671f5d4..4db3b71 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> s\'ha desactivat"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferència"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Descripció emergent"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index fa5b13e..b72ef8b 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – zakázáno"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenční hovor"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Popisek"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index be50bcb..ad01840 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – deaktiveret"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonmøde"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Værktøjstip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 3f64c9b..db19e193 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> deaktiviert"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonkonferenz"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Kurzinfo"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 21d42d9..333adaa 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Απενεργοποιημένο <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Κλήση συνδιάσκεψης"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Επεξήγηση εργαλείου"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 531a5ab..91b1620 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 531a5ab..91b1620 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 531a5ab..91b1620 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Disabled <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index f888bd1..7db3b4c 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Se inhabilitó <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferencia"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Información sobre la herramienta"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 6d88d6f..39ca2ef 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> inhabilitado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferencia"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Descripción emergente"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 01edc01..2ccc3eb 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Keelatud <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konverentskõne"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tööriistavihje"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 3bb4492..c131c42 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desgaituta dago"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferentzia-deia"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Aholkua"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index cb2f57e..d6ef85a 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> غیرفعال شد"</string>
     <string name="conference_call" msgid="3751093130790472426">"تماس کنفرانسی"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"نکته‌ابزار"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index a02017a..943b8e7 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ei ole käytössä."</string>
     <string name="conference_call" msgid="3751093130790472426">"Puhelinneuvottelu"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Työkaluvinkki"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index b864e2b..3deefd3 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1551,7 +1551,7 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"<xliff:g id="LABEL">%1$s</xliff:g> (travail)"</string>
     <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2e <xliff:g id="LABEL">%1$s</xliff:g> professionnel(le)"</string>
     <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3e <xliff:g id="LABEL">%1$s</xliff:g> professionnel(le)"</string>
-    <string name="lock_to_app_toast" msgid="7693684144593484">"Pour annuler l\'épinglage de cet écran, maintenez enfoncée les touches Retour et Aperçu."</string>
+    <string name="lock_to_app_toast" msgid="7693684144593484">"Pour annuler l\'épinglage de cet écran, maintenez enfoncées les touches Retour et Aperçu."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"L\'application est épinglée : l\'annulation de l\'épinglage n\'est pas autorisée sur cet appareil."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"Écran épinglé"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"Épinglage d\'écran annulé"</string>
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Désactivé : <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conférence téléphonique"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Infobulle"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index cd10d36..7abb654 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Élément \"<xliff:g id="LABEL">%1$s</xliff:g>\" désactivé"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conférence téléphonique"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Info-bulle"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index bcf19d9..9b0f666 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -21,7 +21,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="byteShort" msgid="8340973892742019101">"B"</string>
-    <string name="kilobyteShort" msgid="7542884022844556968">"KB"</string>
+    <string name="kilobyteShort" msgid="7542884022844556968">"kB"</string>
     <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
     <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
     <string name="terabyteShort" msgid="231613018159186962">"TB"</string>
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Desactivouse <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferencia telefónica"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Cadro de información"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index a79d53c..db02286 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> અક્ષમ કર્યું"</string>
     <string name="conference_call" msgid="3751093130790472426">"કોન્ફરન્સ કૉલ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ટૂલટિપ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 26a0dcc..29ead1d 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"अक्षम <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"कॉन्फ़्रेंस कॉल"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"टूलटिप"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 683a1a3..8e3ed1c 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1702,4 +1702,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogućeno"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencijski poziv"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Opis"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3c8e390..f58f365 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"A(z) <xliff:g id="LABEL">%1$s</xliff:g> letiltva"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenciahívás"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Elemleírás"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 91cdfa4..c1702c0 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Անջատած <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Կոնֆերանս զանգ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Հուշակ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 58447fa..05560d3 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dinonaktifkan"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferensi Telepon"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Keterangan alat"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 0178b77..573d014 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Slökkt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Símafundur"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Ábending"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 9228b33..74adcca 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> disattivato"</string>
     <string name="conference_call" msgid="3751093130790472426">"Audioconferenza"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Descrizione comando"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index f9e4b34..54c3702 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> הושבת"</string>
     <string name="conference_call" msgid="3751093130790472426">"שיחת ועידה"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"הסבר קצר"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 46c7877..47b0325 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"停止済みの「<xliff:g id="LABEL">%1$s</xliff:g>」"</string>
     <string name="conference_call" msgid="3751093130790472426">"グループ通話"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ツールチップ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 7774c66..fb90136 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"გათიშული <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"საკონფერენციო ზარი"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"მინიშნება"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index d15b017..377f0c9 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> өшірулі"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференциялық қоңырау"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Қалқыма сөзкөмек"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index 549bff2..756465c 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1673,4 +1673,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ដែលបានបិទដំណើរការ"</string>
     <string name="conference_call" msgid="3751093130790472426">"ការហៅជាក្រុម"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ផ្ទាំងលោត"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 163d922..8c8ab2f 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
     <string name="conference_call" msgid="3751093130790472426">"ಕಾನ್ಫರೆನ್ಸ್ ಕರೆ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ಟೂಲ್‌ಟಿಪ್"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index a943f53..f0a214e 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> 사용 중지됨"</string>
     <string name="conference_call" msgid="3751093130790472426">"다자간 통화"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"도움말"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index cdbb17f..f0f1ef8 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> өчүрүлдү"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференц чалуу"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Калкып чыгуучу кеңеш"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 1b8a7a2..0649961 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ປິດການນຳໃຊ້ <xliff:g id="LABEL">%1$s</xliff:g> ແລ້ວ"</string>
     <string name="conference_call" msgid="3751093130790472426">"ການປະຊຸມສາຍ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ຄຳອະທິບາຍເຄື່ອງມື"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 1bcb8ca..bd694dd 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1665,7 +1665,7 @@
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Sutraukti"</string>
     <string name="zen_mode_feature_name" msgid="5254089399895895004">"Netrukdyti"</string>
     <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Prastova"</string>
-    <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Savaitgalio vakarą"</string>
+    <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Darbo dienos vakarą"</string>
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Savaitgalį"</string>
     <string name="zen_mode_default_events_name" msgid="8158334939013085363">"Įvykis"</string>
     <string name="muted_by" msgid="6147073845094180001">"Nutildė <xliff:g id="THIRD_PARTY">%1$s</xliff:g>"</string>
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Išj. valdiklis „<xliff:g id="LABEL">%1$s</xliff:g>“"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferencinis skambutis"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Patarimas"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 0df18d1..d17846f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1702,4 +1702,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> atspējots"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferences zvans"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Rīka padoms"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index a4912c3..7d2ba9d 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1673,4 +1673,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Оневозможен <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференциски повик"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Совет за алатка"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 202e69a..c0be3a4 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> പ്രവർത്തനരഹിതമാക്കി"</string>
     <string name="conference_call" msgid="3751093130790472426">"കോൺഫറൻസ് കോൾ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ടൂൾ ടിപ്പ്"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 1dfb039..9078460 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1669,4 +1669,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g>-г цуцалсан"</string>
     <string name="conference_call" msgid="3751093130790472426">"Хурлын дуудлага"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Зөвлөмж"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 4f4275a..e455178 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -1551,7 +1551,7 @@
     <string name="managed_profile_label_badge" msgid="2355652472854327647">"कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_2" msgid="5048136430082124036">"2 रे कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="managed_profile_label_badge_3" msgid="2808305070321719040">"3 रे कार्य <xliff:g id="LABEL">%1$s</xliff:g>"</string>
-    <string name="lock_to_app_toast" msgid="7693684144593484">"ही स्क्रीन अनपिन करण्यासाठी, परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
+    <string name="lock_to_app_toast" msgid="7693684144593484">"ही स्क्रीन अनपिन करण्यासाठी, परत जा आणि विहंगावलोकन करा स्पर्श करा आणि धरून ठेवा."</string>
     <string name="lock_to_app_toast_locked" msgid="9125176335701699164">"अॅप पिन केलेला आहे: या डिव्हाइसवर अनपिन करण्यास अनुमती नाही."</string>
     <string name="lock_to_app_start" msgid="6643342070839862795">"स्क्रीन पिन केली"</string>
     <string name="lock_to_app_exit" msgid="8598219838213787430">"स्क्रीन अनपिन केली"</string>
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> अक्षम केले"</string>
     <string name="conference_call" msgid="3751093130790472426">"परिषद कॉल"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"टूलटिप"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 69808069..d41ff77 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> dilumpuhkan"</string>
     <string name="conference_call" msgid="3751093130790472426">"Panggilan Sidang"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Keterangan item"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index bada9a9..291d92d 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ပိတ်ထားသည့် <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"လူအမြောက်အမြားတပြိုင်နက် ခေါ်ဆိုမှု"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"အကြံပြုချက်ပြ ပေါ့အပ် ဝင်းဒိုး"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d83e61e..70a8828 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> er slått av"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferansesamtale"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Verktøytips"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index a033cba..0653ab7 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1677,4 +1677,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> लाई असक्षम गरियो"</string>
     <string name="conference_call" msgid="3751093130790472426">"सम्मेलन कल"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"उपकरणको वर्णन"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index b6e2426..2e55648 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> uitgeschakeld"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonische vergadering"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Knopinfo"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 21aeb9d..cff0ddb 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ਅਯੋਗ ਬਣਾਇਆ ਗਿਆ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"ਕਾਨਫਰੰਸ ਕਾਲ"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ਟੂਲਟਿਪ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 57d64ad..45b48f9 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Wyłączono: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Połączenie konferencyjne"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Etykietka"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 094b30b..8b50b0f 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Teleconferência"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Dica"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index c0a73a0..736d6e0 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferência"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Sugestão"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 094b30b..8b50b0f 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Widget <xliff:g id="LABEL">%1$s</xliff:g> desativado"</string>
     <string name="conference_call" msgid="3751093130790472426">"Teleconferência"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Dica"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index e809e3b..43b8f1f 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1702,4 +1702,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> a fost dezactivat"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conferință telefonică"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Balon explicativ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 44b4c51..cd6c871 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Виджет <xliff:g id="LABEL">%1$s</xliff:g> отключен"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференц-связь"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Подсказка"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 2e49ec2..031d9d0 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1673,4 +1673,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"අබල කළ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"සම්මන්ත්‍රණ ඇමතුම"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"මෙවලම් ඉඟිය"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 71a0373..e483d39 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Deaktivovaná miniaplikácia <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenčný hovor"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Popis"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index fbd2fc2..b74875a 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> – onemogočeno"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenčni klic"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Opis orodja"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 51c4b94..536c60f 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> u çaktivizua"</string>
     <string name="conference_call" msgid="3751093130790472426">"Telefonatë konferencë"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Këshilla për veglën"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index c23044c..c7d8fdf 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1702,4 +1702,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Виџет <xliff:g id="LABEL">%1$s</xliff:g> је онемогућен"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференцијски позив"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Објашњење"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index adfd909..f5e3445 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> har inaktiverats"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferenssamtal"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Beskrivning"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index d460fe0..1c91e99 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1669,4 +1669,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> imezimwa"</string>
     <string name="conference_call" msgid="3751093130790472426">"Simu ya Kongamano"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Kidirisha cha vidokezo"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 96a9f48..b04f928 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"முடக்கப்பட்டது: <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"குழு அழைப்பு"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"உதவிக்குறிப்பு"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 4b93693..7f2ffdd 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> నిలిపివేయబడింది"</string>
     <string name="conference_call" msgid="3751093130790472426">"కాన్ఫరెన్స్ కాల్"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"సాధనం చిట్కా"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a46935c..7e2f78c 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"ปิดใช้ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"การประชุมสาย"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"เคล็ดลับเครื่องมือ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index b738ada..f245774 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Na-disable ang <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Conference Call"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Tooltip"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index dea294a..0c3db29 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> devre dışı"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferans Çağrısı"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"İpucu"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 842d06f..19e3798 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1733,4 +1733,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> вимкнено"</string>
     <string name="conference_call" msgid="3751093130790472426">"Конференц-виклик"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Спливаюча підказка"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index bb7a69e..3eb2025 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"غیر فعال کردہ <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"کانفرنس کال"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"ٹول ٹپ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index d8b8e7e..c706816 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"<xliff:g id="LABEL">%1$s</xliff:g> vidjeti o‘chirilgan"</string>
     <string name="conference_call" msgid="3751093130790472426">"Konferens-aloqa"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Maslahat oynasi"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 9d204c2..a406656 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"Đã tắt <xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"Cuộc gọi nhiều bên"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Chú giải công cụ"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6f51494..55773c6 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"已停用的<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"电话会议"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"提示"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index a4723db..300cc36 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"「<xliff:g id="LABEL">%1$s</xliff:g>」已停用"</string>
     <string name="conference_call" msgid="3751093130790472426">"會議通話"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"提示"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index dd37549..ffa10d7 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"已停用的<xliff:g id="LABEL">%1$s</xliff:g>"</string>
     <string name="conference_call" msgid="3751093130790472426">"電話會議"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"工具提示"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 9cb03b8..a5da794 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1671,4 +1671,20 @@
     <string name="suspended_widget_accessibility" msgid="6712143096475264190">"I-<xliff:g id="LABEL">%1$s</xliff:g> ekhutshaziwe"</string>
     <string name="conference_call" msgid="3751093130790472426">"Ikholi yengqungquthela"</string>
     <string name="tooltip_popup_title" msgid="5253721848739260181">"Ithulithiphu"</string>
+    <!-- no translation found for app_category_game (5431836943981492993) -->
+    <skip />
+    <!-- no translation found for app_category_audio (1659853108734301647) -->
+    <skip />
+    <!-- no translation found for app_category_video (2728726078629384196) -->
+    <skip />
+    <!-- no translation found for app_category_image (4867854544519846048) -->
+    <skip />
+    <!-- no translation found for app_category_social (5842783057834965912) -->
+    <skip />
+    <!-- no translation found for app_category_news (7496506240743986873) -->
+    <skip />
+    <!-- no translation found for app_category_maps (5878491404538024367) -->
+    <skip />
+    <!-- no translation found for app_category_productivity (3742083261781538852) -->
+    <skip />
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index dd33718..a5c1a94 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -62,6 +62,8 @@
 
         <!-- Default disabled alpha for widgets that set enabled/disabled alpha programmatically. -->
         <attr name="disabledAlpha" format="float" />
+        <!-- The alpha applied to the foreground color to create the primary text color. -->
+        <attr name="primaryContentAlpha" format="float" />
         <!-- Default background dim amount when a menu, dialog, or something similar pops up. -->
         <attr name="backgroundDimAmount" format="float" />
         <!-- Control whether dimming behind the window is enabled.  The default
@@ -7615,6 +7617,21 @@
     </declare-styleable>
 
     <!-- =============================== -->
+    <!-- AutoFill attributes -->
+    <!-- =============================== -->
+    <eat-comment />
+
+    <!-- Use <code>autofill-service</code> as the root tag of the XML resource that describes a
+         {@link android.service.autofill.AutoFillService}, which is referenced from its
+         {@link android.service.autofill#SERVICE_META_DATA} meta-data entry.
+    -->
+    <declare-styleable name="AutoFillService">
+        <!-- Fully qualified class name of an activity that allows the user to modify
+             the settings for this service. -->
+        <attr name="settingsActivity" />
+    </declare-styleable>
+
+    <!-- =============================== -->
     <!-- Contacts meta-data attributes -->
     <!-- =============================== -->
     <eat-comment />
@@ -8428,7 +8445,7 @@
     <!-- @hide Attributes which will be read by the Activity to intialize the
                base activity TaskDescription. -->
     <declare-styleable name="ActivityTaskDescription">
-        <!-- @hide From Theme.colorPrimary, used for the TaskDescription primary 
+        <!-- @hide From Theme.colorPrimary, used for the TaskDescription primary
                    color. -->
         <attr name="colorPrimary" />
         <!-- @hide From Theme.colorBackground, used for the TaskDescription background
diff --git a/core/res/res/values/colors_material.xml b/core/res/res/values/colors_material.xml
index 40e7341..835b8b60 100644
--- a/core/res/res/values/colors_material.xml
+++ b/core/res/res/values/colors_material.xml
@@ -73,6 +73,8 @@
 
     <item name="disabled_alpha_material_light" format="float" type="dimen">0.26</item>
     <item name="disabled_alpha_material_dark" format="float" type="dimen">0.30</item>
+    <item name="primary_content_alpha_material_light" format="float" type="dimen">1</item>
+    <item name="primary_content_alpha_material_dark" format="float" type="dimen">0.87</item>
 
     <item name="highlight_alpha_material_light" format="float" type="dimen">0.12</item>
     <item name="highlight_alpha_material_dark" format="float" type="dimen">0.20</item>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index db157bf..7de48d3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2710,4 +2710,10 @@
 
     <!-- Component name of the default cell broadcast receiver -->
     <string name="config_defaultCellBroadcastReceiverComponent" translatable="false">com.android.cellbroadcastreceiver/.PrivilegedCellBroadcastReceiver</string>
+
+    <!-- The component name, flattened to a string, for the default accessibility service to be
+         enabled by the accessibility shortcut. This service must be trusted, as it can be activated
+         without explicit consent of the user. If no accessibility service with the specified name
+         exists on the device, the accessibility shortcut will be disabled by default. -->
+    <string name="config_defaultAccessibilityService" translatable="false"></string>
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 064d31e..099fe08 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2793,6 +2793,8 @@
     <public-group type="id" first-id="0x01020041">
     </public-group>
 
+    <public type="attr" name="primaryContentAlpha" />
+
   <!-- ===============================================================
        DO NOT ADD UN-GROUPED ITEMS HERE
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 87a4732..0204e93 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3818,12 +3818,35 @@
        "Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."
     </string>
 
-    <!-- Text spoken when the user is performing a gesture that will enable accessibility. [CHAR LIMIT=none] -->
-    <string name="continue_to_enable_accessibility">Keep holding down two fingers to enable accessibility.</string>
-    <!-- Text spoken when the user enabled accessibility. [CHAR LIMIT=none] -->
-    <string name="accessibility_enabled">Accessibility enabled.</string>
-    <!-- Text spoken when the user stops preforming a gesture that would enable accessibility. [CHAR LIMIT=none] -->
-    <string name="enable_accessibility_canceled">Accessibility canceled.</string>
+    <!-- Dialog title for dialog shown when the accessibility shortcut is activated, and we want
+     to confirm that the user understands what's going to happen-->
+    <string name="accessibility_shortcut_warning_dialog_title">Accessibility Shortcut is ON</string>
+
+    <!-- Message shown in dialog when user is in the process of enabling the accessibility
+    service via the volume buttons shortcut for the first time. [CHAR LIMIT=none] -->
+    <string name="accessibility_shortcut_toogle_warning">
+        Turn <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> on or off by holding down
+        both volume buttons for 3 seconds.\n\nYou can change the service in
+        Settings > Accessibility.
+    </string>
+
+    <!-- Text in button that turns off the accessibility shortcut -->
+    <string name="disable_accessibility_shortcut">Turn Off Shortcut</string>
+
+    <!-- Text in button that closes the warning dialog about the accessibility shortcut, leaving the
+    shortcut enabled.-->
+    <string name="leave_accessibility_shortcut_on">Leave on</string>
+
+    <!-- Text in toast to alert the user that the accessibility shortcut turned on an accessibility
+    service.-->
+    <string name="accessibility_shortcut_enabling_service">Accessibility Shortcut turned
+        <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> on</string>
+
+    <!-- Text in toast to alert the user that the accessibility shortcut turned off an accessibility
+    service.-->
+    <string name="accessibility_shortcut_disabling_service">Accessibility Shortcut turned
+        <xliff:g id="service_name" example="TalkBack">%1$s</xliff:g> off</string>
+
     <!-- Text spoken when the current user is switched if accessibility is enabled. [CHAR LIMIT=none] -->
     <string name="user_switched">Current user <xliff:g id="name" example="Bob">%1$s</xliff:g>.</string>
     <!-- Message shown when switching to a user [CHAR LIMIT=none] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index d46bdcf..c370ef7 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1139,7 +1139,6 @@
   <java-symbol type="string" name="conference_call" />
   <java-symbol type="string" name="tooltip_popup_title" />
 
-
   <java-symbol type="plurals" name="bugreport_countdown" />
   <java-symbol type="plurals" name="last_num_days" />
   <java-symbol type="plurals" name="matches_found" />
@@ -2772,6 +2771,8 @@
 
   <java-symbol type="dimen" name="config_appTransitionAnimationDurationScaleDefault" />
 
+  <java-symbol type="layout" name="notification_template_material_ambient" />
+
   <!-- Network Recommendation -->
   <java-symbol type="array" name="config_networkRecommendationPackageNames" />
 
@@ -2795,4 +2796,14 @@
 
   <java-symbol type="raw" name="fallback_categories" />
 
+  <java-symbol type="attr" name="primaryContentAlpha" />
+
+  <!-- Accessibility Shortcut -->
+  <java-symbol type="string" name="accessibility_shortcut_warning_dialog_title" />
+  <java-symbol type="string" name="accessibility_shortcut_toogle_warning" />
+  <java-symbol type="string" name="accessibility_shortcut_enabling_service" />
+  <java-symbol type="string" name="accessibility_shortcut_disabling_service" />
+  <java-symbol type="string" name="disable_accessibility_shortcut" />
+  <java-symbol type="string" name="leave_accessibility_shortcut_on" />
+  <java-symbol type="string" name="config_defaultAccessibilityService" />
 </resources>
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 5f0ad8e..d0f202b 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -48,13 +48,14 @@
         <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
         <item name="disabledAlpha">@dimen/disabled_alpha_material_dark</item>
+        <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_dark</item>
         <item name="backgroundDimAmount">0.6</item>
 
         <!-- Text styles -->
         <item name="textAppearance">@style/TextAppearance.Material</item>
         <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
 
-        <item name="textColorPrimary">@color/primary_text_material_dark</item>
+        <item name="textColorPrimary">@color/text_color_primary</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
         <item name="textColorPrimaryActivated">@color/primary_text_inverse_when_activated_material</item>
         <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
@@ -413,13 +414,14 @@
         <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
         <item name="disabledAlpha">@dimen/disabled_alpha_material_light</item>
+        <item name="primaryContentAlpha">@dimen/primary_content_alpha_material_light</item>
         <item name="backgroundDimAmount">0.6</item>
 
         <!-- Text styles -->
         <item name="textAppearance">@style/TextAppearance.Material</item>
         <item name="textAppearanceInverse">@style/TextAppearance.Material.Inverse</item>
 
-        <item name="textColorPrimary">@color/primary_text_material_light</item>
+        <item name="textColorPrimary">@color/text_color_primary</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
         <item name="textColorPrimaryActivated">@color/primary_text_inverse_when_activated_material</item>
         <item name="textColorSecondary">@color/secondary_text_material_light</item>
@@ -805,7 +807,7 @@
         <item name="colorBackgroundFloating">@color/background_floating_material_light</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_light</item>
 
-        <item name="textColorPrimary">@color/primary_text_material_light</item>
+        <item name="textColorPrimary">@color/text_color_primary</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_dark</item>
         <item name="textColorSecondary">@color/secondary_text_material_light</item>
         <item name="textColorSecondaryInverse">@color/secondary_text_material_dark</item>
@@ -839,7 +841,7 @@
         <item name="colorBackgroundFloating">@color/background_floating_material_dark</item>
         <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_material_dark</item>
 
-        <item name="textColorPrimary">@color/primary_text_material_dark</item>
+        <item name="textColorPrimary">@color/text_color_primary</item>
         <item name="textColorPrimaryInverse">@color/primary_text_material_light</item>
         <item name="textColorPrimaryDisableOnly">@color/primary_text_disable_only_material_dark</item>
         <item name="textColorSecondary">@color/secondary_text_material_dark</item>
diff --git a/core/tests/ConnectivityManagerTest/Android.mk b/core/tests/ConnectivityManagerTest/Android.mk
index 56011f7..39cf4a4 100644
--- a/core/tests/ConnectivityManagerTest/Android.mk
+++ b/core/tests/ConnectivityManagerTest/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/core/tests/bandwidthtests/Android.mk b/core/tests/bandwidthtests/Android.mk
index cb44721..2af92df 100644
--- a/core/tests/bandwidthtests/Android.mk
+++ b/core/tests/bandwidthtests/Android.mk
@@ -23,6 +23,7 @@
 	$(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := BandwidthTests
 
 include $(BUILD_PACKAGE)
diff --git a/core/tests/bluetoothtests/Android.mk b/core/tests/bluetoothtests/Android.mk
index 4a1d18c..f53419a 100644
--- a/core/tests/bluetoothtests/Android.mk
+++ b/core/tests/bluetoothtests/Android.mk
@@ -9,6 +9,7 @@
 	$(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := BluetoothTests
 LOCAL_CERTIFICATE := platform
 
diff --git a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
index 37f0007..ff98eb7 100644
--- a/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
+++ b/core/tests/coretests/src/android/os/storage/StorageManagerIntegrationTest.java
@@ -18,15 +18,20 @@
 
 import android.content.Context;
 import android.os.Environment;
+import android.os.ProxyFileDescriptorCallback;
+import android.os.ParcelFileDescriptor;
+import android.system.ErrnoException;
+import android.system.Os;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.Suppress;
 import android.util.Log;
 
 import com.android.frameworks.coretests.R;
-
+import com.android.internal.os.FuseAppLoop;
 import java.io.DataInputStream;
 import java.io.IOException;
+import java.util.concurrent.ThreadFactory;
 import java.io.File;
 import java.io.FileInputStream;
 
@@ -243,4 +248,47 @@
         verifyObb1Contents(filePath);
         unmountObb(filePath, DONT_FORCE);
     }
+
+    @LargeTest
+    public void testOpenProxyFileDescriptor() throws Exception {
+        final ProxyFileDescriptorCallback callback = new ProxyFileDescriptorCallback() {
+            @Override
+            public long onGetSize() throws ErrnoException {
+                return 0;
+            }
+
+            @Override
+            public void onRelease() {}
+        };
+
+        final MyThreadFactory factory = new MyThreadFactory();
+        int firstMountId;
+        try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor(
+                ParcelFileDescriptor.MODE_READ_ONLY, callback, factory)) {
+            assertNotSame(Thread.State.TERMINATED, factory.thread.getState());
+            firstMountId = mSm.getProxyFileDescriptorMountPointId();
+            assertNotSame(-1, firstMountId);
+        }
+
+        // After closing descriptor, the loop should terminate.
+        factory.thread.join(3000);
+        assertEquals(Thread.State.TERMINATED, factory.thread.getState());
+
+        // StorageManager should mount another bridge on the next open request.
+        try (final ParcelFileDescriptor fd = mSm.openProxyFileDescriptor(
+                ParcelFileDescriptor.MODE_WRITE_ONLY, callback, factory)) {
+            assertNotSame(Thread.State.TERMINATED, factory.thread.getState());
+            assertNotSame(firstMountId, mSm.getProxyFileDescriptorMountPointId());
+        }
+    }
+
+    private static class MyThreadFactory implements ThreadFactory {
+        Thread thread = null;
+
+        @Override
+        public Thread newThread(Runnable r) {
+            thread = new Thread(r);
+            return thread;
+        }
+    }
 }
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/provider/SettingsProviderTest.java b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
index b0ce2c8..3fbf169 100644
--- a/core/tests/coretests/src/android/provider/SettingsProviderTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsProviderTest.java
@@ -364,4 +364,20 @@
         // one or more activity can handle this intent.
         assertTrue(resolveInfoList.size() > 0);
     }
+
+    @SmallTest
+    public void testValidSsaid() {
+        ContentResolver r = getContext().getContentResolver();
+
+        // Verify ssaid
+        String ssaid = Settings.Secure.getString(r, Settings.Secure.ANDROID_ID);
+        assertTrue(ssaid != null);
+        assertTrue(ssaid.length() == 16);
+
+        String ssaid2 = Settings.Secure.getString(r, Settings.Secure.ANDROID_ID);
+        assertTrue(ssaid2 != null);
+        assertTrue(ssaid2.length() == 16);
+
+        assertTrue(ssaid.equals(ssaid2));
+    }
 }
diff --git a/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java b/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
index e3f754c..a340559 100644
--- a/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
+++ b/core/tests/coretests/src/com/android/internal/logging/LogBuilderTest.java
@@ -1,5 +1,21 @@
+/*
+ * 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.internal.logging;
 
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import junit.framework.TestCase;
 
 public class LogBuilderTest extends TestCase {
@@ -15,6 +31,57 @@
         assertEquals("two", out[3]);
     }
 
+    public void testSerializeDeserialize() {
+        int category = 10;
+        int type = 11;
+        int subtype = 12;
+        long timestamp = 1484669007890L;
+        String packageName = "com.foo.bar";
+        String counterName = "sheep";
+        int bucket = 13;
+        int value = 14;
+
+        LogBuilder builder = new LogBuilder(category);
+        builder.setType(type);
+        builder.setSubtype(subtype);
+        builder.setTimestamp(timestamp);
+        builder.setPackageName(packageName);
+        builder.setCounterName(counterName);
+        builder.setCounterBucket(bucket);
+        builder.setCounterValue(value);
+        builder.addTaggedData(1, "one");
+        builder.addTaggedData(2, "two");
+
+        Object[] out = builder.serialize();
+        LogBuilder parsed = new LogBuilder(out);
+
+        assertEquals(category, parsed.getCategory());
+        assertEquals(type, parsed.getType());
+        assertEquals(subtype, parsed.getSubtype());
+        assertEquals(timestamp, parsed.getTimestamp());
+        assertEquals(packageName, parsed.getPackageName());
+        assertEquals(counterName, parsed.getCounterName());
+        assertEquals(bucket, parsed.getCounterBucket());
+        assertEquals(value, parsed.getCounterValue());
+        assertEquals("one", parsed.getTaggedData(1));
+        assertEquals("two", parsed.getTaggedData(2));
+    }
+
+    public void testIntBucket() {
+        LogBuilder builder = new LogBuilder(0);
+        builder.setCounterBucket(100);
+        assertEquals(100, builder.getCounterBucket());
+        assertEquals(false, builder.isLongCounterBucket());
+    }
+
+    public void testLongBucket() {
+        long longBucket = Long.MAX_VALUE;
+        LogBuilder builder = new LogBuilder(0);
+        builder.setCounterBucket(longBucket);
+        assertEquals(longBucket, builder.getCounterBucket());
+        assertEquals(true, builder.isLongCounterBucket());
+    }
+
     public void testInvalidInputThrows() {
         LogBuilder builder = new LogBuilder(0);
         boolean threw = false;
@@ -24,7 +91,7 @@
             threw = true;
         }
         assertTrue(threw);
-        assertEquals(0, builder.serialize().length);
+        assertEquals(2, builder.serialize().length);
     }
 
     public void testValidInputTypes() {
@@ -40,4 +107,11 @@
         assertEquals(123.0F, out[7]);
     }
 
+  public void testCategoryDefault() {
+        LogBuilder builder = new LogBuilder(10);
+        Object[] out = builder.serialize();
+        assertEquals(MetricsEvent.RESERVED_FOR_LOGBUILDER_CATEGORY, out[0]);
+        assertEquals(10, out[1]);
+    }
+
 }
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/CounterParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/CounterParserTest.java
new file mode 100644
index 0000000..5a7766b
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/CounterParserTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+public class CounterParserTest extends ParserTest {
+
+    public CounterParserTest() {
+        mParser = new CounterParser();
+    }
+
+    public void testGoodData() throws Throwable {
+        String name = "foo";
+        int value = 5;
+        Object[] objects = new Object[2];
+        objects[0] = name;
+        objects[1] = value;
+
+        validateGoodData(name, value, objects);
+    }
+
+    private void validateGoodData(String name, int value, Object[] objects) {
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, times(1)).incrementBy(mNameCaptor.capture(), mCountCaptor.capture());
+
+        assertEquals(TronCounters.TRON_AOSP_PREFIX + name, mNameCaptor.getValue());
+        assertEquals(value, mCountCaptor.getValue().intValue());
+    }
+
+    public void testMissingName() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testWrongTypes() throws Throwable {
+        String name = "foo";
+        int value = 5;
+        Object[] objects = new Object[2];
+        objects[0] = value;
+        objects[1] = name;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreMissingInput() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        String name = "foo";
+        int value = 5;
+        Object[] objects = new Object[3];
+        objects[0] = name;
+        objects[1] = value;
+        objects[2] = "foo";
+
+        validateGoodData(name, value, objects);
+    }
+
+
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/HistogramParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/HistogramParserTest.java
new file mode 100644
index 0000000..1bd9d83
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/HistogramParserTest.java
@@ -0,0 +1,90 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+public class HistogramParserTest extends ParserTest {
+
+    public HistogramParserTest() {
+        mParser = new HistogramParser();
+    }
+
+    public void testGoodData() throws Throwable {
+        String name = "foo";
+        int bucket = 5;
+        Object[] objects = new Object[2];
+        objects[0] = name;
+        objects[1] = bucket;
+
+        validateGoodData(name, bucket, objects);
+    }
+
+    private void validateGoodData(String name, int bucket, Object[] objects) {
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, times(1))
+                .incrementIntHistogram(mNameCaptor.capture(), mCountCaptor.capture());
+
+        assertEquals(TronCounters.TRON_AOSP_PREFIX + name, mNameCaptor.getValue());
+        assertEquals(bucket, mCountCaptor.getValue().intValue());
+    }
+
+    public void testMissingName() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testWrongTypes() throws Throwable {
+        String name = "foo";
+        int value = 5;
+        Object[] objects = new Object[2];
+        objects[0] = value;
+        objects[1] = name;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreMissingInput() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        String name = "foo";
+        int bucket = 5;
+        Object[] objects = new Object[3];
+        objects[0] = name;
+        objects[1] = bucket;
+        objects[2] = "foo";
+
+        validateGoodData(name, bucket, objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/LockscreenGestureParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/LockscreenGestureParserTest.java
new file mode 100644
index 0000000..0bff850
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/LockscreenGestureParserTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class LockscreenGestureParserTest extends ParserTest {
+
+    public LockscreenGestureParserTest() {
+        mParser = new LockscreenGestureParser();
+    }
+
+    public void testSwipeUpUnlock() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_UNLOCK, 1, 359, 6382);
+    }
+
+    public void testSwipeToShade() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_SHADE, 2, 324, 0);
+    }
+
+    public void testTapLockHint() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_HINT, 3, 0, 0);
+    }
+
+    public void testCamera() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_CAMERA, 4, 223, 1756);
+    }
+
+    public void testDialer() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_DIALER, 5, 163, 861);
+    }
+
+    public void testTapToLock() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_LOCK, 6, 0, 0);
+    }
+
+    public void testTapOnNotification() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_NOTE, 7, 0, 0);
+    }
+
+    public void testLockscreenQuickSettings() throws Throwable {
+        validate(MetricsEvent.ACTION_LS_QS, 8, 284, 3824);
+    }
+
+    public void testShadePullQuickSettings() throws Throwable {
+        validate(MetricsEvent.ACTION_SHADE_QS_PULL, 9, 175, 3444);
+    }
+
+    public void testShadeTapQuickSettings() throws Throwable {
+        validate(MetricsEvent.ACTION_SHADE_QS_TAP, 10, 0, 0);
+    }
+
+    private void validate(int view, int type, int len, int vel) {
+        int t = 1000;
+        Object[] objects = new Object[3];
+        objects[0] = type;
+        objects[1] = len;
+        objects[2] = vel;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[4];
+        objects[0] = 1;
+        objects[1] = 0;
+        objects[2] = 0;
+        objects[3] = "foo";
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent((LogBuilder) anyObject());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationActionClickedParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationActionClickedParserTest.java
new file mode 100644
index 0000000..2119c25
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationActionClickedParserTest.java
@@ -0,0 +1,123 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class NotificationActionClickedParserTest extends ParserTest {
+
+    public NotificationActionClickedParserTest() {
+        mParser = new NotificationActionClickedParser();
+    }
+
+    public void testGoodData() throws Throwable {
+        int t = 1000;
+        int index = 1;
+        Object[] objects = new Object[2];
+        objects[0] = mKey;
+        objects[1] = index;
+
+        validateGoodData(t, "", index, objects);
+    }
+
+    public void testTagged() throws Throwable {
+        int t = 1000;
+        int index = 1;
+        Object[] objects = new Object[2];
+        objects[0] = mTaggedKey;
+        objects[1] = index;
+
+        validateGoodData(t, mTag, index, objects);
+    }
+
+    private LogBuilder validateGoodData(int t, String tag, int index, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ITEM_ACTION, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, tag);
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+        assertEquals(index, proto.getSubtype());
+        return proto;
+    }
+
+    public void testMissingData() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testWrongType() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = 2;
+        objects[1] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testBadKey() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = "foo";
+        objects[1] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testMncTimestamps() throws Throwable {
+        int t = 1000;
+        int index = 1;
+        Object[] objects = new Object[5];
+        objects[0] = mKey;
+        objects[1] = index;
+        objects[2] = mSinceCreationMillis;
+        objects[3] = mSinceUpdateMillis;
+        objects[4] = mSinceVisibleMillis;
+
+        LogBuilder proto = validateGoodData(t, "", index, objects);
+        validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
+                mSinceVisibleMillis);
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int index = 1;
+        Object[] objects = new Object[6];
+        objects[0] = mKey;
+        objects[1] = index;
+        objects[2] = mSinceCreationMillis;
+        objects[3] = mSinceUpdateMillis;
+        objects[4] = mSinceVisibleMillis;
+        objects[5] = "foo";
+
+        validateGoodData(t, "", index, objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationAlertParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationAlertParserTest.java
new file mode 100644
index 0000000..1e117ee
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationAlertParserTest.java
@@ -0,0 +1,138 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.mockito.ArgumentCaptor;
+
+public class NotificationAlertParserTest extends ParserTest {
+    protected ArgumentCaptor<Boolean> mConfigCaptor;
+
+    private final int mTime = 1000;
+
+    public NotificationAlertParserTest() {
+        mParser = new NotificationAlertParser();
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mConfigCaptor = ArgumentCaptor.forClass(Boolean.class);
+        when(mLogger.getConfig(anyString())).thenReturn(false);
+    }
+
+    public void testBuzzOnly() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 1;
+        objects[2] = 0;
+        objects[3] = 0;
+
+        validateInteraction(true, false, false, objects);
+    }
+
+    public void testBeepOnly() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 0;
+        objects[2] = 1;
+        objects[3] = 0;
+
+        validateInteraction(false, true, false, objects);
+    }
+
+    public void testBlinkOnly() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 0;
+        objects[2] = 0;
+        objects[3] = 1;
+
+        validateInteraction(false, false, true, objects);
+    }
+
+    public void testBuzzBlink() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 1;
+        objects[2] = 0;
+        objects[3] = 1;
+
+        validateInteraction(true, false, true, objects);
+    }
+
+    public void testBeepBlink() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 0;
+        objects[2] = 1;
+        objects[3] = 1;
+
+        validateInteraction(false, true, true, objects);
+    }
+
+    public void testIgnoreExtraArgs() throws Throwable {
+        Object[] objects = new Object[5];
+        objects[0] = mTaggedKey;
+        objects[1] = 0;
+        objects[2] = 1;
+        objects[3] = 1;
+        objects[4] = "foo";
+
+        validateInteraction(false, true, true, objects);
+    }
+
+    private void validateInteraction(boolean buzz, boolean beep, boolean blink, Object[] objects) {
+        int flags = 0;
+        int counts = 0;
+        if (buzz) {
+            counts++;
+            flags |= NotificationAlertParser.BUZZ;
+        }
+        if (beep) {
+            counts++;
+            flags |= NotificationAlertParser.BEEP;
+        }
+        if (blink) {
+            counts++;
+            flags |= NotificationAlertParser.BLINK;
+        }
+
+        mParser.parseEvent(mLogger, mTime, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(mTime, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ALERT, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, mTag);
+        assertEquals(flags, proto.getSubtype());
+        assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
+
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationCanceledParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationCanceledParserTest.java
new file mode 100644
index 0000000..de16919
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationCanceledParserTest.java
@@ -0,0 +1,200 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Mockito.anyObject;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import java.util.List;
+
+public class NotificationCanceledParserTest extends ParserTest {
+
+    public NotificationCanceledParserTest() {
+        mParser = new NotificationCanceledParser();
+    }
+
+    public void testGoodProto() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[2];
+        objects[0] = mKey;
+        objects[1] = reason;
+
+        validateGoodData(t, "", reason, objects);
+    }
+
+    public void testTagged() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[2];
+        objects[0] = mTaggedKey;
+        objects[1] = reason;
+
+        validateGoodData(t, mTag, reason, objects);
+    }
+
+    private void validateGoodData(int t, String tag, int reason, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, tag);
+        assertEquals(MetricsEvent.TYPE_DISMISS, proto.getType());
+        assertEquals(reason, proto.getSubtype());
+    }
+
+    public void testLifetime() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = reason;
+        objects[2] = mSinceCreationMillis;
+
+        validateTimers(t, objects, mSinceCreationMillis, 0, 0);
+    }
+
+    public void testExposure() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[4];
+        objects[0] = mKey;
+        objects[1] = reason;
+        objects[2] = mSinceCreationMillis;
+        objects[3] = mSinceVisibleMillis;
+
+
+        validateTimers(t, objects, mSinceCreationMillis, 0, mSinceVisibleMillis);
+    }
+
+    public void testFreshness() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[5];
+        objects[0] = mKey;
+        objects[1] = reason;
+        objects[2] = mSinceCreationMillis;
+        objects[3] = mSinceUpdateMillis;
+        objects[4] = mSinceVisibleMillis;
+
+        validateTimers(t, objects, mSinceCreationMillis, mSinceUpdateMillis, mSinceVisibleMillis);
+    }
+
+    private void validateTimers(int t, Object[] objects, int life, int freshness, int exposure) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        validateNotificationTimes(proto, life, freshness, exposure);
+    }
+
+    public void verifyReason(int reason, boolean intentional, boolean important, String counter)
+            throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = mKey;
+        objects[1] = reason;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        if (intentional) {
+            verify(mLogger, times(1)).addEvent((LogBuilder) anyObject());
+        }
+    }
+
+    public void testDelegateCancel() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_DELEGATE_CANCEL,
+                true, true, TronCounters.TRON_NOTE_DISMISS_BY_USER);
+    }
+
+    public void testDelegateCancelAll() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_DELEGATE_CANCEL_ALL,
+                true, true, TronCounters.TRON_NOTE_DISMISS_BY_USER);
+    }
+
+    public void testListenerCancel() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_LISTENER_CANCEL,
+                false, true, TronCounters.TRON_NOTE_DISMISS_BY_LISTENER);
+    }
+
+    public void testListenerCancelAll() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_LISTENER_CANCEL_ALL,
+                false, true, TronCounters.TRON_NOTE_DISMISS_BY_LISTENER);
+    }
+
+    public void testDelegateClick() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_DELEGATE_CLICK,
+                true, true, TronCounters.TRON_NOTE_DISMISS_BY_CLICK);
+    }
+
+    public void testBanned() throws Throwable {
+        verifyReason(NotificationCanceledParser.REASON_PACKAGE_BANNED,
+                false, true, TronCounters.TRON_NOTE_DISMISS_BY_BAN);
+    }
+
+    public void testUnknownReason() throws Throwable {
+        verifyReason(1001010, false, false, TronCounters.TRON_NOTE_DISMISS_BY_BAN);
+    }
+
+    public void testMissingData() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testWrongType() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = 2;
+        objects[1] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testBadKey() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = "foo";
+        objects[1] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int reason = NotificationCanceledParser.REASON_DELEGATE_CANCEL;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = reason;
+        objects[2] = "foo";
+
+        validateGoodData(t, "", reason, objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationClickedParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationClickedParserTest.java
new file mode 100644
index 0000000..2f61dd7
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationClickedParserTest.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 com.android.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class NotificationClickedParserTest extends ParserTest {
+
+    public NotificationClickedParserTest() {
+        mParser = new NotificationClickedParser();
+    }
+
+    public void testGoodData() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[1];
+        objects[0] = mKey;
+
+        validateGoodData(t, "", objects);
+    }
+
+    public void testTagged() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[1];
+        objects[0] = mTaggedKey;
+
+        validateGoodData(t, mTag, objects);
+    }
+
+    private LogBuilder validateGoodData(int t, String tag, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, tag);
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+        assertEquals(0, proto.getSubtype());
+        return proto;
+    }
+
+    public void testMissingKey() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testWrongType() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = 5;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testBadKey() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = "foo";
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testMncTimestamps() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[4];
+        objects[0] = mKey;
+        objects[1] = mSinceCreationMillis;
+        objects[2] = mSinceUpdateMillis;
+        objects[3] = mSinceVisibleMillis;
+
+        LogBuilder proto = validateGoodData(t, "", objects);
+        validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
+                mSinceVisibleMillis);
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[5];
+        objects[0] = mKey;
+        objects[1] = mSinceCreationMillis;
+        objects[2] = mSinceUpdateMillis;
+        objects[3] = mSinceVisibleMillis;
+        objects[4] = "foo";
+
+        validateGoodData(t, "", objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationExpansionParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationExpansionParserTest.java
new file mode 100644
index 0000000..86b4a45
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationExpansionParserTest.java
@@ -0,0 +1,175 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class NotificationExpansionParserTest extends ParserTest {
+
+    public NotificationExpansionParserTest() {
+        mParser = new NotificationExpansionParser();
+    }
+
+    public void testExpandedByUser() throws Throwable {
+        int t = 1000;
+        int byUser = 1;
+        int expanded = 1;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+
+        validateGoodData(t, "", objects);
+    }
+
+    public void testTagged() throws Throwable {
+        int t = 1000;
+        int byUser = 1;
+        int expanded = 1;
+        Object[] objects = new Object[3];
+        objects[0] = mTaggedKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+
+        validateGoodData(t, mTag, objects);
+    }
+
+    private LogBuilder validateGoodData(int t, String tag, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, tag);
+        assertEquals(MetricsEvent.TYPE_DETAIL, proto.getType());
+        return proto;
+    }
+
+    public void testAutoExpand() throws Throwable {
+        int t = 1000;
+        int byUser = 0;
+        int expanded = 1;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testCollapsedByUser() throws Throwable {
+        int t = 1000;
+        int byUser = 1;
+        int expanded = 0;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testAutoCollapsed() throws Throwable {
+        int t = 1000;
+        int byUser = 0;
+        int expanded = 0;
+        Object[] objects = new Object[3];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testMissingData() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testWrongType() throws Throwable {
+        Object[] objects = new Object[3];
+        objects[0] = 2;
+        objects[1] = 5;
+        objects[2] = 7;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testBadKey() throws Throwable {
+        Object[] objects = new Object[3];
+        objects[0] = "foo";
+        objects[1] = 5;
+        objects[2] = 2;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testMncTimestamps() throws Throwable {
+        int t = 1000;
+        int byUser = 1;
+        int expanded = 1;
+        Object[] objects = new Object[6];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+        objects[3] = mSinceCreationMillis;
+        objects[4] = mSinceUpdateMillis;
+        objects[5] = mSinceVisibleMillis;
+
+        LogBuilder proto = validateGoodData(t, "", objects);
+        validateNotificationTimes(proto, mSinceCreationMillis, mSinceUpdateMillis,
+                mSinceVisibleMillis);
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int byUser = 1;
+        int expanded = 1;
+        Object[] objects = new Object[7];
+        objects[0] = mKey;
+        objects[1] = byUser;
+        objects[2] = expanded;
+        objects[3] = mSinceCreationMillis;
+        objects[4] = mSinceUpdateMillis;
+        objects[5] = mSinceVisibleMillis;
+        objects[6] = "foo";
+
+        validateGoodData(t, "", objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationKeyTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationKeyTest.java
new file mode 100644
index 0000000..b509700
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationKeyTest.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.internal.logging.legacy;
+
+import android.test.InstrumentationTestCase;
+
+public class NotificationKeyTest extends InstrumentationTestCase {
+
+    private final NotificationKey mKey;
+
+    public NotificationKeyTest() {
+        mKey = new NotificationKey();
+    }
+
+    public void testGoodKey() throws Throwable {
+        assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338|null|10090"));
+
+        assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
+        assertEquals("", mKey.mTag);
+        assertEquals(31338, mKey.mId);
+        assertEquals(1, mKey.mUser);
+        assertEquals(10090, mKey.mUid);
+    }
+
+    public void testTaggedKey() throws Throwable {
+        assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338|foo|10090"));
+
+        assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
+        assertEquals("foo", mKey.mTag);
+        assertEquals(31338, mKey.mId);
+        assertEquals(1, mKey.mUser);
+        assertEquals(10090, mKey.mUid);
+    }
+
+    public void testEmptyTag() throws Throwable {
+        assertTrue(mKey.parse("1|com.android.example.notificationshowcase|31338||10090"));
+
+        assertEquals("com.android.example.notificationshowcase", mKey.mPackageName);
+        assertEquals("", mKey.mTag);
+        assertEquals(31338, mKey.mId);
+        assertEquals(1, mKey.mUser);
+        assertEquals(10090, mKey.mUid);
+    }
+
+    public void testBadKeys() throws Throwable {
+        assertFalse(mKey.parse(null));
+        assertFalse(mKey.parse(""));
+        assertFalse(mKey.parse("foo"));  // not a key
+        assertFalse(mKey.parse("1|com.android.example.notificationshowcase|31338|null"));
+        assertFalse(mKey.parse("bar|com.android.example.notificationshowcase|31338|null|10090"));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelHiddenParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelHiddenParserTest.java
new file mode 100644
index 0000000..3efc48f
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelHiddenParserTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class NotificationPanelHiddenParserTest extends ParserTest {
+
+    public NotificationPanelHiddenParserTest() {
+        mParser = new NotificationPanelHiddenParser();
+    }
+
+    public void testNoInput() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[0];
+
+        validateGoodData(t, objects);
+
+    }
+
+    public void testIgnoreExtraneousInput() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = "nothing to see here";
+
+        validateGoodData(0, objects);
+    }
+
+    private void validateGoodData(int t, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_CLOSE, proto.getType());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelRevealedParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelRevealedParserTest.java
new file mode 100644
index 0000000..34dda98
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationPanelRevealedParserTest.java
@@ -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 com.android.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class NotificationPanelRevealedParserTest extends ParserTest {
+
+    public NotificationPanelRevealedParserTest() {
+        mParser = new NotificationPanelRevealedParser();
+    }
+
+    public void testLollipopInput() throws Throwable {
+        int t = 1000;
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
+    }
+
+    public void testMncData() throws Throwable {
+        int t = 1000;
+        int n = 5;
+        Object[] objects = new Object[1];
+        objects[0] = Integer.valueOf(n);
+
+        validateMncData(t, n, objects);
+    }
+
+    private void validateMncData(int t, int n, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_PANEL, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
+    }
+
+    public void testBadInput() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = "This is not the integer you're looking for.";
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, times(1)).addEvent((LogBuilder) anyObject());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int n = 5;
+        Object[] objects = new Object[2];
+        objects[0] = Integer.valueOf(n);
+        objects[1] = "foo";
+
+        validateMncData(t, n, objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationVisibilityParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationVisibilityParserTest.java
new file mode 100644
index 0000000..cc5421c
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/NotificationVisibilityParserTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import org.mockito.ArgumentCaptor;
+
+public class NotificationVisibilityParserTest extends ParserTest {
+    private final int mCreationTime = 23124;
+    private final int mUpdateTime = 3412;
+    private final int mTime = 1000;
+
+    public NotificationVisibilityParserTest() {
+        mParser = new NotificationVisibilityParser();
+    }
+
+    public void testReveal() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 1;
+        objects[2] = mCreationTime;
+        objects[3] = mUpdateTime;
+
+        validateInteraction(true, mUpdateTime, 0, objects);
+    }
+
+    public void testHide() throws Throwable {
+        Object[] objects = new Object[4];
+        objects[0] = mTaggedKey;
+        objects[1] = 0;
+        objects[2] = mCreationTime;
+        objects[3] = mUpdateTime;
+
+        validateInteraction(false, mUpdateTime, 0, objects);
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        Object[] objects = new Object[5];
+        objects[0] = mTaggedKey;
+        objects[1] = 1;
+        objects[2] = mCreationTime;
+        objects[3] = mUpdateTime;
+        objects[4] = "foo";
+
+        validateInteraction(true, mUpdateTime, 0, objects);
+    }
+
+    public void testMarshmallowIndexData() throws Throwable {
+        Object[] objects = new Object[6];
+        objects[0] = mTaggedKey;
+        objects[1] = 1;
+        objects[2] = mCreationTime;
+        objects[3] = mUpdateTime;
+        objects[4] = 0;
+        objects[5] = 3;
+
+        validateInteraction(true, mUpdateTime, 3, objects);
+    }
+
+    private void validateInteraction(boolean visible, int freshness, int index, Object[] objects)    {
+        mParser.parseEvent(mLogger, mTime, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(mTime, proto.getTimestamp());
+        assertEquals(MetricsEvent.NOTIFICATION_ITEM, proto.getCategory());
+        assertEquals(mKeyPackage, proto.getPackageName());
+        validateNotificationIdAndTag(proto, mId, mTag);
+        validateNotificationTimes(proto, mCreationTime, mUpdateTime);
+        assertEquals(index, proto.getTaggedData(MetricsEvent.NOTIFICATION_SHADE_INDEX));
+        assertEquals(visible ? MetricsEvent.TYPE_OPEN : MetricsEvent.TYPE_CLOSE, proto.getType());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/ParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/ParserTest.java
new file mode 100644
index 0000000..2e5c6d2
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/ParserTest.java
@@ -0,0 +1,111 @@
+/*
+ * 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.internal.logging.legacy;
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.when;
+
+import junit.framework.TestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.OngoingStubbing;
+
+/**
+ * Common functions and temporaries for parser tests.
+ */
+public class ParserTest extends TestCase {
+    @Mock
+    protected TronLogger mLogger;
+
+    protected TagParser mParser;
+
+    protected LogBuilder[] mProto;
+    protected ArgumentCaptor<LogBuilder> mProtoCaptor;
+    protected ArgumentCaptor<String> mNameCaptor;
+    protected ArgumentCaptor<Integer> mCountCaptor;
+    protected String mKey = "0|com.android.example.notificationshowcase|31338|null|10090";
+    protected String mTaggedKey = "0|com.android.example.notificationshowcase|31338|badger|10090";
+    protected String mKeyPackage = "com.android.example.notificationshowcase";
+    protected String mTag = "badger";
+    protected int mId = 31338;
+    protected int mSinceCreationMillis = 5000;
+    protected int mSinceUpdateMillis = 1012;
+    protected int mSinceVisibleMillis = 323;
+
+
+    public ParserTest() {
+        mProto = new LogBuilder[5];
+        for (int i = 0; i < mProto.length; i++) {
+            mProto[i] = new LogBuilder(MetricsEvent.VIEW_UNKNOWN);
+        }
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        MockitoAnnotations.initMocks(this);
+
+        mProtoCaptor = ArgumentCaptor.forClass(LogBuilder.class);
+        mNameCaptor = ArgumentCaptor.forClass(String.class);
+        mCountCaptor = ArgumentCaptor.forClass(Integer.class);
+
+        OngoingStubbing<LogBuilder> stub = when(mLogger.obtain()).thenReturn(mProto[0]);
+        for (int i = 1; i < mProto.length; i++) {
+            stub.thenReturn(mProto[i]);
+        }
+        doNothing().when(mLogger).addEvent(any(LogBuilder.class));
+        doNothing().when(mLogger).incrementBy(anyString(), anyInt());
+    }
+
+    protected void validateNotificationTimes(LogBuilder proto, int life, int freshness,
+            int exposure) {
+        validateNotificationTimes(proto, life, freshness);
+        if (exposure != 0) {
+            assertEquals(exposure,
+                proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS));
+        } else {
+            assertNull(proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_VISIBLE_MILLIS));
+        }
+    }
+
+    protected void validateNotificationTimes(LogBuilder proto, int life, int freshness) {
+        if (life != 0) {
+            assertEquals(life,
+                proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS));
+        } else {
+            assertNull(proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_CREATE_MILLIS));
+        }
+        if (freshness != 0) {
+            assertEquals(freshness,
+                proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS));
+        } else {
+            assertNull(proto.getTaggedData(MetricsEvent.NOTIFICATION_SINCE_UPDATE_MILLIS));
+        }
+    }
+
+    protected void validateNotificationIdAndTag(LogBuilder proto, int id, String tag) {
+        assertEquals(tag, proto.getTaggedData(MetricsEvent.NOTIFICATION_TAG));
+        assertEquals(id, proto.getTaggedData(MetricsEvent.NOTIFICATION_ID));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/PowerScreenStateParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/PowerScreenStateParserTest.java
new file mode 100644
index 0000000..be918cd
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/PowerScreenStateParserTest.java
@@ -0,0 +1,69 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class PowerScreenStateParserTest extends ParserTest {
+
+    public PowerScreenStateParserTest() {
+        mParser = new PowerScreenStateParser();
+    }
+
+    public void testScreenOn() throws Throwable {
+        validate(MetricsEvent.TYPE_OPEN, 0, "1,0,0,0");
+    }
+
+    public void testTimeout() throws Throwable {
+        validate(MetricsEvent.TYPE_CLOSE, 3, "0,3,0,0");
+    }
+
+    public void testUser() throws Throwable {
+        validate(MetricsEvent.TYPE_CLOSE, 2, "0,2,0,0");
+    }
+
+    public void testAdmin() throws Throwable {
+        validate(MetricsEvent.TYPE_CLOSE, 1, "0,1,0,0");
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        validate(MetricsEvent.TYPE_OPEN, 0, "1,0,0,0,5");
+    }
+
+    private void validate(int type, int subType, String log) {
+        String[] parts = log.split(",");
+        int t = 1000;
+        Object[] objects = new Object[parts.length];
+        for (int i = 0; i < parts.length; i++) {
+            objects[i] = Integer.valueOf(parts[i]);
+        }
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(type, proto.getType());
+        assertEquals(MetricsEvent.SCREEN, proto.getCategory());
+        assertEquals(subType, proto.getSubtype());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/StatusBarStateParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/StatusBarStateParserTest.java
new file mode 100644
index 0000000..906ec04
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/StatusBarStateParserTest.java
@@ -0,0 +1,73 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class StatusBarStateParserTest extends ParserTest {
+
+    public StatusBarStateParserTest() {
+        mParser = new StatusBarStateParser();
+    }
+
+    public void testLockScreen() throws Throwable {
+        validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 1, "1,1,0,0,1,0");
+    }
+
+    public void testBounce() throws Throwable {
+        validate(MetricsEvent.BOUNCER, MetricsEvent.TYPE_OPEN, 1, "1,1,0,1,1,0");
+    }
+
+    public void testUnlock() throws Throwable {
+        validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_CLOSE, 1, "0,0,0,0,1,0");
+    }
+
+    public void testSecure() throws Throwable {
+        validate(MetricsEvent.BOUNCER, MetricsEvent.TYPE_OPEN, 1, "2,1,0,1,1,0");
+    }
+
+    public void testInsecure() throws Throwable {
+        validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 0, "1,1,0,0,0,0");
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        validate(MetricsEvent.LOCKSCREEN, MetricsEvent.TYPE_OPEN, 0, "1,1,0,0,0,0,5");
+    }
+
+    private void validate(int view, int type, int subType, String log) {
+        String[] parts = log.split(",");
+        int t = 1000;
+        Object[] objects = new Object[parts.length];
+        for (int i = 0; i < parts.length; i++) {
+            objects[i] = Integer.valueOf(parts[i]);
+        }
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(type, proto.getType());
+        assertEquals(subType, proto.getSubtype());
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiActionParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiActionParserTest.java
new file mode 100644
index 0000000..111909f
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiActionParserTest.java
@@ -0,0 +1,167 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class SysuiActionParserTest extends ParserTest {
+
+    public SysuiActionParserTest() {
+        mParser = new SysuiActionParser();
+    }
+
+    public void testGoodDatal() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[1];
+        objects[0] = view;
+
+        validateGoodData(t, view, objects);
+    }
+
+    private void validateGoodData(int t, int view, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+    }
+
+    public void testGoodDataWithPackage() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        String packageName = "com.foo";
+        Object[] objects = new Object[2];
+        objects[0] = view;
+        objects[1] = packageName;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(packageName, proto.getPackageName());
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+    }
+
+    public void testGoodDataWithTrue() throws Throwable {
+        validateSubType(Boolean.toString(true), 1);
+    }
+
+    public void testGoodDataWithFalse() throws Throwable {
+        validateSubType(Boolean.toString(false), 0);
+    }
+
+    public void testGoodDataWithIntZero() throws Throwable {
+        validateSubType(Integer.toString(0), 0);
+    }
+
+    public void testGoodDataWithIntONe() throws Throwable {
+        validateSubType(Integer.toString(1), 1);
+    }
+
+    public void testGoodDataWithIntTwo() throws Throwable {
+        validateSubType(Integer.toString(2), 2);
+    }
+
+    public void testGoodDataWithNegativeInt() throws Throwable {
+        validateSubType(Integer.toString(-1), -1);
+    }
+
+    public void testGoodDataWithIntLarge() throws Throwable {
+        validateSubType(Integer.toString(120312), 120312);
+    }
+
+    public void testGoodDataWithNegativeIntLarge() throws Throwable {
+        validateSubType(Integer.toString(-120312), -120312);
+    }
+
+    private void validateSubType(String arg, int expectedValue) {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[2];
+        objects[0] = view;
+        objects[1] = arg;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(expectedValue, proto.getSubtype());
+        assertNull(proto.getPackageName());
+        assertEquals(MetricsEvent.TYPE_ACTION, proto.getType());
+    }
+
+    public void testIgnoreMissingInput() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreWrongInputs() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = "nothing to see here";
+        objects[1] = 10;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreStringViewInput() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = "this is not the input you are looking for";
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[2];
+        objects[0] = view;
+        objects[1] = "foo";
+
+        validateGoodData(t, view, objects);
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiMultiActionParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiMultiActionParserTest.java
new file mode 100644
index 0000000..7853f77
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiMultiActionParserTest.java
@@ -0,0 +1,72 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class SysuiMultiActionParserTest extends ParserTest {
+
+    public SysuiMultiActionParserTest() {
+        mParser = new SysuiMultiActionParser();
+    }
+
+    public void testParseAllFields() {
+        int category = 10;
+        int type = 11;
+        int subtype = 12;
+        long timestamp = 1484669007890L;
+        String packageName = "com.foo.bar";
+        String counterName = "sheep";
+        int bucket = 13;
+        int value = 14;
+        LogBuilder builder = new LogBuilder(category);
+        builder.setType(type);
+        builder.setSubtype(subtype);
+        builder.setPackageName(packageName);
+        builder.setCounterName(counterName);
+        builder.setCounterBucket(bucket);
+        builder.setCounterValue(value);
+        builder.addTaggedData(1, "one");
+        builder.addTaggedData(2, "two");
+        Object[] out = builder.serialize();
+        int t = 1000;
+
+        mParser.parseEvent(mLogger, timestamp, out);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(category, proto.getCategory());
+        assertEquals(type, proto.getType());
+        assertEquals(subtype, proto.getSubtype());
+        assertEquals(timestamp, proto.getTimestamp());
+        assertEquals(packageName, proto.getPackageName());
+        assertEquals(counterName, proto.getCounterName());
+        assertEquals(bucket, proto.getCounterBucket());
+        assertEquals(value, proto.getCounterValue());
+        assertEquals("one", proto.getTaggedData(1));
+        assertEquals("two", proto.getTaggedData(2));
+    }
+}
diff --git a/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiViewVisibilityParserTest.java b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiViewVisibilityParserTest.java
new file mode 100644
index 0000000..1291508
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/logging/legacy/SysuiViewVisibilityParserTest.java
@@ -0,0 +1,122 @@
+/*
+ * 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.internal.logging.legacy;
+
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
+
+import com.android.internal.logging.LogBuilder;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
+public class SysuiViewVisibilityParserTest extends ParserTest {
+
+    public SysuiViewVisibilityParserTest() {
+        mParser = new SysuiViewVisibilityParser();
+    }
+
+    public void testViewReveal() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[2];
+        objects[0] = view;
+        objects[1] = 100;
+
+        validateViewReveal(t, view, objects);
+    }
+
+    private void validateViewReveal(int t, int view, Object[] objects) {
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(t, proto.getTimestamp());
+        assertEquals(view, proto.getCategory());
+        assertEquals(MetricsEvent.TYPE_OPEN, proto.getType());
+    }
+
+    public void testViewHidden() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[2];
+        objects[0] = view;
+        objects[1] = 0;
+
+        mParser.parseEvent(mLogger, t, objects);
+
+        verify(mLogger, times(1)).addEvent(mProtoCaptor.capture());
+
+        LogBuilder proto = mProtoCaptor.getValue();
+        assertEquals(MetricsEvent.TYPE_CLOSE, proto.getType());
+    }
+
+    public void testIgnoreMissingInput() throws Throwable {
+        Object[] objects = new Object[0];
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreStringInARgOne() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = "nothing to see here";
+        objects[1] = 100;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreStringInArgTwo() throws Throwable {
+        Object[] objects = new Object[2];
+        objects[0] = 100;
+        objects[1] = "nothing to see here";
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testOneInput() throws Throwable {
+        Object[] objects = new Object[1];
+        objects[0] = 100;
+
+        mParser.parseEvent(mLogger, 0, objects);
+
+        verify(mLogger, never()).addEvent((LogBuilder) anyObject());
+        verify(mLogger, never()).incrementBy(anyString(), anyInt());
+    }
+
+    public void testIgnoreUnexpectedData() throws Throwable {
+        int t = 1000;
+        int view = 10;
+        Object[] objects = new Object[3];
+        objects[0] = view;
+        objects[1] = 100;
+        objects[2] = "foo";
+
+        validateViewReveal(t, view, objects);
+    }
+}
diff --git a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
index 97e8b1f..47ee2cf 100644
--- a/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
+++ b/core/tests/hosttests/test-apps/DownloadManagerTestApp/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-common mockwebserver
+LOCAL_STATIC_JAVA_LIBRARIES := android-common mockwebserver junit legacy-android-test
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_PACKAGE_NAME := DownloadManagerTestApp
diff --git a/core/tests/notificationtests/Android.mk b/core/tests/notificationtests/Android.mk
index 702218c..0551eb6 100644
--- a/core/tests/notificationtests/Android.mk
+++ b/core/tests/notificationtests/Android.mk
@@ -12,6 +12,8 @@
 LOCAL_PACKAGE_NAME := NotificationStressTests
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
+    junit \
+    legacy-android-test \
     ub-uiautomator
 
 include $(BUILD_PACKAGE)
diff --git a/core/tests/utillib/Android.mk b/core/tests/utillib/Android.mk
index 299ea5a..8811256 100644
--- a/core/tests/utillib/Android.mk
+++ b/core/tests/utillib/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_MODULE := frameworks-core-util-lib
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 include $(BUILD_STATIC_JAVA_LIBRARY)
 
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 05db9b0..f1be4a9 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -110,11 +110,21 @@
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
     </privapp-permissions>
 
+    <privapp-permissions package="com.android.omadm.service">
+        <permission name="android.permission.CHANGE_CONFIGURATION"/>
+        <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
+        <permission name="android.permission.MODIFY_PHONE_STATE"/>
+        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
+        <permission name="android.permission.WRITE_APN_SETTINGS"/>
+        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
+    </privapp-permissions>
+
     <privapp-permissions package="com.android.packageinstaller">
         <permission name="android.permission.CLEAR_APP_CACHE"/>
         <permission name="android.permission.DELETE_PACKAGES"/>
         <permission name="android.permission.INSTALL_PACKAGES"/>
         <permission name="android.permission.MANAGE_USERS"/>
+        <permission name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"/>
         <permission name="android.permission.UPDATE_APP_OPS_STATS"/>
     </privapp-permissions>
 
@@ -122,6 +132,7 @@
         <permission name="android.permission.ACCESS_IMS_CALL_SERVICE"/>
         <permission name="android.permission.BIND_CARRIER_MESSAGING_SERVICE"/>
         <permission name="android.permission.BIND_CARRIER_SERVICES"/>
+        <permission name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"/>
         <permission name="android.permission.CALL_PRIVILEGED"/>
         <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
         <permission name="android.permission.CHANGE_CONFIGURATION"/>
@@ -327,4 +338,4 @@
         <permission name="android.permission.CONTROL_VPN"/>
     </privapp-permissions>
 
-</permissions>
+</permissions>
\ No newline at end of file
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index f135484..2ebd2cc 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -58,6 +58,7 @@
             throw new RuntimeException("Canvas: trying to use a non-premultiplied bitmap "
                     + bitmap);
         }
+        throwIfHwBitmapInSwMode(bitmap);
     }
 
     protected final static void checkRange(int length, int offset, int count) {
@@ -80,12 +81,14 @@
 
     public void drawArc(float left, float top, float right, float bottom, float startAngle,
             float sweepAngle, boolean useCenter, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle,
                 useCenter, paint.getNativeInstance());
     }
 
     public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
             @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
                 paint);
     }
@@ -96,12 +99,14 @@
 
     public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
         throwIfCannotDraw(bitmap);
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top,
                 paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity,
                 bitmap.mDensity);
     }
 
     public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap, matrix.ni(),
                 paint != null ? paint.getNativeInstance() : 0);
     }
@@ -112,6 +117,7 @@
             throw new NullPointerException();
         }
         throwIfCannotDraw(bitmap);
+        throwIfHasHwBitmapInSwMode(paint);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
 
         int left, top, right, bottom;
@@ -137,6 +143,7 @@
             throw new NullPointerException();
         }
         throwIfCannotDraw(bitmap);
+        throwIfHasHwBitmapInSwMode(paint);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
 
         float left, top, right, bottom;
@@ -175,6 +182,7 @@
                 || (lastScanline + width > length)) {
             throw new ArrayIndexOutOfBoundsException();
         }
+        throwIfHasHwBitmapInSwMode(paint);
         // quick escape if there's nothing to draw
         if (width == 0 || height == 0) {
             return;
@@ -198,6 +206,7 @@
         if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) {
             throw new ArrayIndexOutOfBoundsException();
         }
+        throwIfHasHwBitmapInSwMode(paint);
         if (meshWidth == 0 || meshHeight == 0) {
             return;
         }
@@ -214,6 +223,7 @@
     }
 
     public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.getNativeInstance());
     }
 
@@ -227,19 +237,23 @@
 
     public void drawLine(float startX, float startY, float stopX, float stopY,
             @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.getNativeInstance());
     }
 
     public void drawLines(@Size(multiple = 4) @NonNull float[] pts, int offset, int count,
             @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawLines(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
     }
 
     public void drawLines(@Size(multiple = 4) @NonNull float[] pts, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         drawLines(pts, 0, pts.length, paint);
     }
 
     public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
     }
 
@@ -247,6 +261,7 @@
         if (oval == null) {
             throw new NullPointerException();
         }
+        throwIfHasHwBitmapInSwMode(paint);
         drawOval(oval.left, oval.top, oval.right, oval.bottom, paint);
     }
 
@@ -257,6 +272,7 @@
     public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) {
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
+        throwIfHasHwBitmapInSwMode(paint);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
         nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint,
@@ -266,6 +282,7 @@
     public void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint) {
         Bitmap bitmap = patch.getBitmap();
         throwIfCannotDraw(bitmap);
+        throwIfHasHwBitmapInSwMode(paint);
         final long nativePaint = paint == null ? 0 : paint.getNativeInstance();
         nDrawNinePatch(mNativeCanvasWrapper, bitmap.getNativeInstance(), patch.mNativeChunk,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint,
@@ -273,6 +290,7 @@
     }
 
     public void drawPath(@NonNull Path path, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         if (path.isSimplePath && path.rects != null) {
             nDrawRegion(mNativeCanvasWrapper, path.rects.mNativeRegion, paint.getNativeInstance());
         } else {
@@ -281,15 +299,18 @@
     }
 
     public void drawPoint(float x, float y, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawPoint(mNativeCanvasWrapper, x, y, paint.getNativeInstance());
     }
 
     public void drawPoints(@Size(multiple = 2) float[] pts, int offset, int count,
             @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawPoints(mNativeCanvasWrapper, pts, offset, count, paint.getNativeInstance());
     }
 
     public void drawPoints(@Size(multiple = 2) @NonNull float[] pts, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         drawPoints(pts, 0, pts.length, paint);
     }
 
@@ -300,6 +321,7 @@
         if (index < 0 || index + count > text.length || count * 2 > pos.length) {
             throw new IndexOutOfBoundsException();
         }
+        throwIfHasHwBitmapInSwMode(paint);
         for (int i = 0; i < count; i++) {
             drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint);
         }
@@ -308,18 +330,22 @@
     @Deprecated
     public void drawPosText(@NonNull String text, @NonNull @Size(multiple = 2) float[] pos,
             @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         drawPosText(text.toCharArray(), 0, text.length(), pos, paint);
     }
 
     public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.getNativeInstance());
     }
 
     public void drawRect(@NonNull Rect r, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         drawRect(r.left, r.top, r.right, r.bottom, paint);
     }
 
     public void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawRect(mNativeCanvasWrapper,
                 rect.left, rect.top, rect.right, rect.bottom, paint.getNativeInstance());
     }
@@ -330,11 +356,13 @@
 
     public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
             @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry,
                 paint.getNativeInstance());
     }
 
     public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
     }
 
@@ -344,6 +372,7 @@
                 (text.length - index - count)) < 0) {
             throw new IndexOutOfBoundsException();
         }
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags,
                 paint.getNativeInstance(), paint.mNativeTypeface);
     }
@@ -353,6 +382,7 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
+        throwIfHasHwBitmapInSwMode(paint);
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             nDrawText(mNativeCanvasWrapper, text.toString(), start, end, x, y,
@@ -370,6 +400,7 @@
     }
 
     public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
                 paint.getNativeInstance(), paint.mNativeTypeface);
     }
@@ -379,6 +410,7 @@
         if ((start | end | (end - start) | (text.length() - end)) < 0) {
             throw new IndexOutOfBoundsException();
         }
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags,
                 paint.getNativeInstance(), paint.mNativeTypeface);
     }
@@ -388,6 +420,7 @@
         if (index < 0 || index + count > text.length) {
             throw new ArrayIndexOutOfBoundsException();
         }
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawTextOnPath(mNativeCanvasWrapper, text, index, count,
                 path.readOnlyNI(), hOffset, vOffset,
                 paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
@@ -396,6 +429,7 @@
     public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,
             float vOffset, @NonNull Paint paint) {
         if (text.length() > 0) {
+            throwIfHasHwBitmapInSwMode(paint);
             nDrawTextOnPath(mNativeCanvasWrapper, text, path.readOnlyNI(), hOffset, vOffset,
                     paint.mBidiFlags, paint.getNativeInstance(), paint.mNativeTypeface);
         }
@@ -416,6 +450,7 @@
             throw new IndexOutOfBoundsException();
         }
 
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawTextRun(mNativeCanvasWrapper, text, index, count, contextIndex, contextCount,
                 x, y, isRtl, paint.getNativeInstance(), paint.mNativeTypeface);
     }
@@ -434,6 +469,7 @@
             throw new IndexOutOfBoundsException();
         }
 
+        throwIfHasHwBitmapInSwMode(paint);
         if (text instanceof String || text instanceof SpannedString ||
                 text instanceof SpannableString) {
             nDrawTextRun(mNativeCanvasWrapper, text.toString(), start, end, contextStart,
@@ -469,11 +505,38 @@
         if (indices != null) {
             checkRange(indices.length, indexOffset, indexCount);
         }
+        throwIfHasHwBitmapInSwMode(paint);
         nDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts,
                 vertOffset, texs, texOffset, colors, colorOffset,
                 indices, indexOffset, indexCount, paint.getNativeInstance());
     }
 
+    private void throwIfHwBitmapInSwMode(Bitmap bitmap) {
+        if (!isHardwareAccelerated() && bitmap.getConfig() == Bitmap.Config.HARDWARE) {
+            throw new IllegalStateException("Software rendering doesn't support hardware bitmaps");
+        }
+    }
+
+    private void throwIfHasHwBitmapInSwMode(Paint p) {
+        if (isHardwareAccelerated() || p == null) {
+            return;
+        }
+        throwIfHasHwBitmapInSwMode(p.getShader());
+    }
+
+    private void throwIfHasHwBitmapInSwMode(Shader shader) {
+        if (shader == null) {
+            return;
+        }
+        if (shader instanceof BitmapShader) {
+            throwIfHwBitmapInSwMode(((BitmapShader) shader).mBitmap);
+        }
+        if (shader instanceof ComposeShader) {
+            throwIfHasHwBitmapInSwMode(((ComposeShader) shader).mShaderA);
+            throwIfHasHwBitmapInSwMode(((ComposeShader) shader).mShaderB);
+        }
+    }
+
     private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top,
             long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity);
 
diff --git a/graphics/java/android/graphics/Color.java b/graphics/java/android/graphics/Color.java
index a2c104a..ff21cac 100644
--- a/graphics/java/android/graphics/Color.java
+++ b/graphics/java/android/graphics/Color.java
@@ -16,27 +16,278 @@
 
 package android.graphics;
 
+import android.annotation.AnyThread;
 import android.annotation.ColorInt;
+import android.annotation.ColorLong;
+import android.annotation.HalfFloat;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.annotation.Size;
 
+import android.util.Half;
 import com.android.internal.util.XmlUtils;
 
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Locale;
 import java.util.function.DoubleUnaryOperator;
 
 /**
- * The Color class defines methods for creating and converting color ints.
- * Colors are represented as packed ints, made up of 4 bytes: alpha, red,
- * green, blue. The values are unpremultiplied, meaning any transparency is
- * stored solely in the alpha component, and not in the color components. The
- * components are stored as follows (alpha << 24) | (red << 16) |
- * (green << 8) | blue. Each component ranges between 0..255 with 0
- * meaning no contribution for that component, and 255 meaning 100%
- * contribution. Thus opaque-black would be 0xFF000000 (100% opaque but
- * no contributions from red, green, or blue), and opaque-white would be
- * 0xFFFFFFFF
+ * {@usesMathJax}
+ *
+ * <p>The <code>Color</code> class provides methods for creating, converting and
+ * manipulating colors. Colors have three different representations:</p>
+ * <ul>
+ *     <li>Color ints, the most common representation</li>
+ *     <li>Color longs</li>
+ *     <li><code>Color</code> instances</li>
+ * </ul>
+ * <p>The section below describe each representation in detail.</p>
+ *
+ * <h3>Color ints</h3>
+ * <p>Color ints are the most common representation of colors on Android and
+ * have been used since {@link android.os.Build.VERSION_CODES#BASE API level 1}.</p>
+ *
+ * <p>A color int always defines a color in the {@link ColorSpace.Named#SRGB sRGB}
+ * color space using 4 components packed in a single 32 bit integer value:</p>
+ *
+ * <table summary="Color int definition">
+ *     <tr>
+ *         <th>Component</th><th>Name</th><th>Size</th><th>Range</th>
+ *     </tr>
+ *     <tr><td>A</td><td>Alpha</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>R</td><td>Red</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>G</td><td>Green</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>B</td><td>Blue</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ * </table>
+ *
+ * <p>The components in this table are listed in encoding order (see below),
+ * which is why color ints are called ARGB colors.</p>
+ *
+ * <h4>Usage in code</h4>
+ * <p>To avoid confusing color ints with arbitrary integer values, it is a
+ * good practice to annotate them with the <code>@ColorInt</code> annotation
+ * found in the Android Support Library.</p>
+ *
+ * <h4>Encoding</h4>
+ * <p>The four components of a color int are encoded in the following way:</p>
+ * <pre class="prettyprint">
+ * int color = (A & 0xff) << 24 | (R & 0xff) << 16 | (G & 0xff) << 16 | (B & 0xff);
+ * </pre>
+ *
+ * <p>Because of this encoding, color ints can easily be described as an integer
+ * constant in source. For instance, opaque blue is <code>0xff0000ff</code>
+ * and yellow is <code>0xffffff00</code>.</p>
+ *
+ * <p>To easily encode color ints, it is recommended to use the static methods
+ * {@link #argb(int, int, int, int)} and {@link #rgb(int, int, int)}. The second
+ * method omits the alpha component and assumes the color is opaque (alpha is 255).
+ * As a convenience this class also offers methods to encode color ints from components
+ * defined in the \([0..1]\) range: {@link #argb(float, float, float, float)} and
+ * {@link #rgb(float, float, float)}.</p>
+ *
+ * <p>Color longs (defined below) can be easily converted to color ints by invoking
+ * the {@link #toArgb(long)} method. This method performs a color space conversion
+ * if needed.</p>
+ *
+ * <p>It is also possible to create a color int by invoking the method {@link #toArgb()}
+ * on a color instance.</p>
+ *
+ * <h4>Decoding</h4>
+ * <p>The four ARGB components can be individually extracted from a color int
+ * using the following expressions:</p>
+ * <pre class="prettyprint">
+ * int A = (color >> 24) & 0xff; // or color >>> 24
+ * int R = (color >> 16) & 0xff;
+ * int G = (color >>  8) & 0xff;
+ * int B = (color      ) & 0xff;
+ * </pre>
+ *
+ * <p>This class offers convenience methods to easily extract these components:</p>
+ * <ul>
+ *     <li>{@link #alpha(int)} to extract the alpha component</li>
+ *     <li>{@link #red(int)} to extract the red component</li>
+ *     <li>{@link #green(int)} to extract the green component</li>
+ *     <li>{@link #blue(int)} to extract the blue component</li>
+ * </ul>
+ *
+ * <h3>Color longs</h3>
+ * <p>Color longs are a representation introduced in
+ * {@link android.os.Build.VERSION_CODES#O Android O} to store colors in different
+ * {@link ColorSpace color spaces}, with more precision than color ints.</p>
+ *
+ * <p>A color long always defines a color using 4 components packed in a single
+ * 64 bit long value. One of these components is always alpha while the other
+ * three components depend on the color space's {@link ColorSpace.Model color model}.
+ * The most common color model is the {@link ColorSpace.Model#RGB RGB} model in
+ * which the components represent red, green and blue values.</p>
+ *
+ * <p class="note"><b>Component ranges:</b> the ranges defined in the tables
+ * below indicate the ranges that can be encoded in a color long. They do not
+ * represent the actual ranges as they may differ per color space. For instance,
+ * the RGB components of a color in the {@link ColorSpace.Named#DISPLAY_P3 Display P3}
+ * color space use the \([0..1]\) range. Please refer to the documentation of the
+ * various {@link ColorSpace.Named color spaces} to find their respective ranges.</p>
+ *
+ * <p class="note"><b>Alpha range:</b> while alpha is encoded in a color long using
+ * a 10 bit integer (thus using a range of \([0..1023]\)), it is converted to and
+ * from \([0..1]\) float values when decoding and encoding color longs.</p>
+ *
+ * <p class="note"><b>sRGB color space:</b> for compatibility reasons and ease of
+ * use, color longs encoding {@link ColorSpace.Named#SRGB sRGB} colors do not
+ * use the same encoding as other color longs.</p>
+ *
+ * <table summary="Color long definition">
+ *     <tr>
+ *         <th>Component</th><th>Name</th><th>Size</th><th>Range</th>
+ *     </tr>
+ *     <tr><td colspan="4">{@link ColorSpace.Model#RGB RGB} color model</td></tr>
+ *     <tr><td>R</td><td>Red</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>G</td><td>Green</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>B</td><td>Blue</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>A</td><td>Alpha</td><td>10 bits</td><td>\([0..1023]\)</td></tr>
+ *     <tr><td></td><td>Color space</td><td>6 bits</td><td>\([0..63]\)</td></tr>
+ *     <tr><td colspan="4">{@link ColorSpace.Named#SRGB sRGB} color space</td></tr>
+ *     <tr><td>A</td><td>Alpha</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>R</td><td>Red</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>G</td><td>Green</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>B</td><td>Blue</td><td>8 bits</td><td>\([0..255]\)</td></tr>
+ *     <tr><td>X</td><td>Unused</td><td>32 bits</td><td>\(0\)</td></tr>
+ *     <tr><td colspan="4">{@link ColorSpace.Model#XYZ XYZ} color model</td></tr>
+ *     <tr><td>X</td><td>X</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>Y</td><td>Y</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>Z</td><td>Z</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>A</td><td>Alpha</td><td>10 bits</td><td>\([0..1023]\)</td></tr>
+ *     <tr><td></td><td>Color space</td><td>6 bits</td><td>\([0..63]\)</td></tr>
+ *     <tr><td colspan="4">{@link ColorSpace.Model#XYZ Lab} color model</td></tr>
+ *     <tr><td>L</td><td>L</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>a</td><td>a</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>b</td><td>b</td><td>16 bits</td><td>\([-65504.0, 65504.0]\)</td></tr>
+ *     <tr><td>A</td><td>Alpha</td><td>10 bits</td><td>\([0..1023]\)</td></tr>
+ *     <tr><td></td><td>Color space</td><td>6 bits</td><td>\([0..63]\)</td></tr>
+ *     <tr><td colspan="4">{@link ColorSpace.Model#CMYK CMYK} color model</td></tr>
+ *     <tr><td colspan="4">Unsupported</td></tr>
+ * </table>
+ *
+ * <p>The components in this table are listed in encoding order (see below),
+ * which is why color longs in the RGB model are called RGBA colors (even if
+ * this doesn't quite hold for the special case of sRGB colors).</p>
+ *
+ * <p>The color long encoding relies on half-precision float values (fp16). If you
+ * wish to know more about the limitations of half-precision float values, please
+ * refer to the documentation of the {@link Half} class.</p>
+ *
+ * <h4>Usage in code</h4>
+ * <p>To avoid confusing color longs with arbitrary long values, it is a
+ * good practice to annotate them with the <code>@ColorLong</code> annotation
+ * found in the Android Support Library.</p>
+ *
+ * <h4>Encoding</h4>
+ *
+ * <p>Given the complex nature of color longs, it is strongly encouraged to use
+ * the various methods provided by this class to encode them.</p>
+ *
+ * <p>The most flexible way to encode a color long is to use the method
+ * {@link #pack(float, float, float, float, ColorSpace)}. This method allows you
+ * to specify three color components (typically RGB), an alpha component and a
+ * color space. To encode sRGB colors, use {@link #pack(float, float, float)}
+ * and {@link #pack(float, float, float, float)} which are the
+ * equivalent of {@link #rgb(int, int, int)} and {@link #argb(int, int, int, int)}
+ * for color ints. If you simply need to convert a color int into a color long,
+ * use {@link #pack(int)}.</p>
+ *
+ * <p>It is also possible to create a color long value by invoking the method
+ * {@link #pack()} on a color instance.</p>
+ *
+ * <h4>Decoding</h4>
+ *
+ * <p>This class offers convenience methods to easily extract the components
+ * of a color long:</p>
+ * <ul>
+ *     <li>{@link #alpha(long)} to extract the alpha component</li>
+ *     <li>{@link #red(long)} to extract the red/X/L component</li>
+ *     <li>{@link #green(long)} to extract the green/Y/a component</li>
+ *     <li>{@link #blue(long)} to extract the blue/Z/b component</li>
+ * </ul>
+ *
+ * <p>The values returned by these methods depend on the color space encoded
+ * in the color long. The values are however typically in the \([0..1]\) range
+ * for RGB colors. Please refer to the documentation of the various
+ * {@link ColorSpace.Named color spaces} for the exact ranges.</p>
+ *
+ * <h3>Color instances</h3>
+ * <p>Color instances are a representation introduced in
+ * {@link android.os.Build.VERSION_CODES#O Android O} to store colors in different
+ * {@link ColorSpace color spaces}, with more precision than both color ints and
+ * color longs. Color instances also offer the ability to store more than 4
+ * components if necessary.</p>
+ *
+ * <p>Colors instances are immutable and can be created using one of the various
+ * <code>valueOf</code> methods. For instance:</p>
+ * <pre class="prettyprint">
+ * // sRGB
+ * Color opaqueRed = Color.valueOf(0xffff0000); // from a color int
+ * Color translucentRed = Color.valueOf(1.0f, 0.0f, 0.0f, 0.5f);
+ *
+ * // Wide gamut color
+ * {@literal @}ColorLong long p3 = pack(1.0f, 1.0f, 0.0f, 1.0f, colorSpaceP3);
+ * Color opaqueYellow = Color.valueOf(p3); // from a color long
+ *
+ * // CIE L*a*b* color space
+ * ColorSpace lab = ColorSpace.get(ColorSpace.Named.LAB);
+ * Color green = Color.valueOf(100.0f, -128.0f, 128.0f, 1.0f, lab);
+ * </pre>
+ *
+ * <p>Color instances can be converted to color ints ({@link #toArgb()}) or
+ * color longs ({@link #pack()}). They also offer easy access to their various
+ * components using the following methods:</p>
+ * <ul>
+ *     <li>{@link #alpha()}, returns the alpha component value</li>
+ *     <li>{@link #red()}, returns the red component value (or first
+ *     component value in non-RGB models)</li>
+ *     <li>{@link #green()}, returns the green component value (or second
+ *     component value in non-RGB models)</li>
+ *     <li>{@link #blue()}, returns the blue component value (or third
+ *     component value in non-RGB models)</li>
+ *     <li>{@link #getComponent(int)}, returns a specific component value</li>
+ *     <li>{@link #getComponents()}, returns all component values as an array</li>
+ * </ul>
+ *
+ * <h3>Color space conversions</h3>
+ * <p>You can convert colors from one color space to another using
+ * {@link ColorSpace#connect(ColorSpace, ColorSpace)} and its variants. However,
+ * the <code>Color</code> class provides a few convenience methods to simplify
+ * the process. Here is a brief description of some of them:</p>
+ * <ul>
+ *     <li>{@link #convert(ColorSpace)} to convert a color instance in a color
+ *     space to a new color instance in a different color space</li>
+ *     <li>{@link #convert(float, float, float, float, ColorSpace, ColorSpace)} to
+ *     convert a color from a source color space to a destination color space</li>
+ *     <li>{@link #convert(long, ColorSpace)} to convert a color long from its
+ *     built-in color space to a destination color space</li>
+ *     <li>{@link #convert(int, ColorSpace)} to convert a color int from sRGB
+ *     to a destination color space</li>
+ * </ul>
+ *
+ * <p>Please refere to the {@link ColorSpace} documentation for more
+ * information.</p>
+ *
+ * <h3>Alpha and transparency</h3>
+ * <p>The alpha component of a color defines the level of transparency of a
+ * color. When the alpha component is 0, the color is completely transparent.
+ * When the alpha is component is 1 (in the \([0..1]\) range) or 255 (in the
+ * \([0..255]\) range), the color is completely opaque.</p>
+ *
+ * <p>The color representations described above do not use pre-multiplied
+ * color components (a pre-multiplied color component is a color component
+ * that has been multiplied by the value of the alpha component).
+ * For instance, the color int representation of opaque red is
+ * <code>0xffff0000</code>. For semi-transparent (50%) red, the
+ * representation becomes <code>0x80ff0000</code>. The equivalent color
+ * instance representations would be <code>(1.0, 0.0, 0.0, 1.0)</code>
+ * and <code>(1.0, 0.0, 0.0, 0.5)</code>.</p>
  */
+@AnyThread
 public class Color {
     @ColorInt public static final int BLACK       = 0xFF000000;
     @ColorInt public static final int DKGRAY      = 0xFF444444;
@@ -51,10 +302,905 @@
     @ColorInt public static final int MAGENTA     = 0xFFFF00FF;
     @ColorInt public static final int TRANSPARENT = 0;
 
+    @NonNull
+    @Size(min = 4, max = 5)
+    private final float[] mComponents;
+
+    @NonNull
+    private final ColorSpace mColorSpace;
+
+    /**
+     * Creates a new color instance set to opaque black in the
+     * {@link ColorSpace.Named#SRGB sRGB} color space.
+     *
+     * @see #valueOf(float, float, float)
+     * @see #valueOf(float, float, float, float)
+     * @see #valueOf(float, float, float, float, ColorSpace)
+     * @see #valueOf(float[], ColorSpace)
+     * @see #valueOf(int)
+     * @see #valueOf(long)
+     */
+    public Color() {
+        // This constructor is required for compatibility with previous APIs
+        mComponents = new float[] { 0.0f, 0.0f, 0.0f, 1.0f };
+        mColorSpace = ColorSpace.get(ColorSpace.Named.SRGB);
+    }
+
+    /**
+     * Creates a new color instance in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
+     *
+     * @param r The value of the red channel, must be in [0..1] range
+     * @param g The value of the green channel, must be in [0..1] range
+     * @param b The value of the blue channel, must be in [0..1] range
+     * @param a The value of the alpha channel, must be in [0..1] range
+     */
+    private Color(float r, float g, float b, float a) {
+        this(r, g, b, a, ColorSpace.get(ColorSpace.Named.SRGB));
+    }
+
+    /**
+     * Creates a new color instance in the specified color space. The color space
+     * must have a 3 components model.
+     *
+     * @param r The value of the red channel, must be in the color space defined range
+     * @param g The value of the green channel, must be in the color space defined range
+     * @param b The value of the blue channel, must be in the color space defined range
+     * @param a The value of the alpha channel, must be in [0..1] range
+     * @param colorSpace This color's color space, cannot be null
+     */
+    private Color(float r, float g, float b, float a, @NonNull ColorSpace colorSpace) {
+        mComponents = new float[] { r, g, b, a };
+        mColorSpace = colorSpace;
+    }
+
+    /**
+     * Creates a new color instance in the specified color space.
+     *
+     * @param components An array of color components, plus alpha
+     * @param colorSpace This color's color space, cannot be null
+     */
+    private Color(@Size(min = 4, max = 5) float[] components, @NonNull ColorSpace colorSpace) {
+        mComponents = components;
+        mColorSpace = colorSpace;
+    }
+
+    /**
+     * Returns this color's color space.
+     *
+     * @return A non-null instance of {@link ColorSpace}
+     */
+    @NonNull
+    public ColorSpace getColorSpace() {
+        return mColorSpace;
+    }
+
+    /**
+     * Returns the color model of this color.
+     *
+     * @return A non-null {@link ColorSpace.Model}
+     */
+    public ColorSpace.Model getModel() {
+        return mColorSpace.getModel();
+    }
+
+    /**
+     * Indicates whether this color color is in a wide-gamut color space.
+     * See {@link ColorSpace#isWideGamut()} for a definition of a wide-gamut
+     * color space.
+     *
+     * @return True if this color is in a wide-gamut color space, false otherwise
+     *
+     * @see #isSrgb()
+     * @see ColorSpace#isWideGamut()
+     */
+    public boolean isWideGamut() {
+        return getColorSpace().isWideGamut();
+    }
+
+    /**
+     * Indicates whether this color is in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
+     *
+     * @return True if this color is in the sRGB color space, false otherwise
+     *
+     * @see #isWideGamut()
+     */
+    public boolean isSrgb() {
+        return getColorSpace().isSrgb();
+    }
+
+    /**
+     * Returns the number of components that form a color value according
+     * to this color space's color model, plus one extra component for
+     * alpha.
+     *
+     * @return An integer between 4 and 5
+     */
+    @IntRange(from = 4, to = 5)
+    public int getComponentCount() {
+        return mColorSpace.getComponentCount() + 1;
+    }
+
+    /**
+     * Packs this color into a color long. See the documentation of this class
+     * for a description of the color long format.
+     *
+     * @return A color long
+     *
+     * @throws IllegalArgumentException If this color's color space has the id
+     * {@link ColorSpace#MIN_ID} or if this color has more than 4 components
+     */
+    @ColorLong
+    public long pack() {
+        return pack(mComponents[0], mComponents[1], mComponents[2], mComponents[3], mColorSpace);
+    }
+
+    /**
+     * Converts this color from its color space to the specified color space.
+     * The conversion is done using the default rendering intent as specified
+     * by {@link ColorSpace#connect(ColorSpace, ColorSpace)}.
+     *
+     * @param colorSpace The destination color space, cannot be null
+     *
+     * @return A non-null color instance in the specified color space
+     */
+    @NonNull
+    public Color convert(@NonNull ColorSpace colorSpace) {
+        ColorSpace.Connector connector = ColorSpace.connect(mColorSpace, colorSpace);
+        float[] color = new float[] {
+                mComponents[0], mComponents[1], mComponents[2], mComponents[3]
+        };
+        connector.transform(color);
+        return new Color(color, colorSpace);
+    }
+
+    /**
+     * Converts this color to an ARGB color int. A color int is always in
+     * the {@link ColorSpace.Named#SRGB sRGB} color space. This implies
+     * a color space conversion is applied if needed.
+     *
+     * @return An ARGB color in the sRGB color space
+     */
+    @ColorInt
+    public int toArgb() {
+        if (mColorSpace.isSrgb()) {
+            return ((int) (mComponents[3] * 255.0f + 0.5f) << 24) |
+                   ((int) (mComponents[0] * 255.0f + 0.5f) << 16) |
+                   ((int) (mComponents[1] * 255.0f + 0.5f) <<  8) |
+                    (int) (mComponents[2] * 255.0f + 0.5f);
+        }
+
+        float[] color = new float[] {
+                mComponents[0], mComponents[1], mComponents[2], mComponents[3]
+        };
+        // The transformation saturates the output
+        ColorSpace.connect(mColorSpace).transform(color);
+
+        return ((int) (color[3] * 255.0f + 0.5f) << 24) |
+               ((int) (color[0] * 255.0f + 0.5f) << 16) |
+               ((int) (color[1] * 255.0f + 0.5f) <<  8) |
+                (int) (color[2] * 255.0f + 0.5f);
+    }
+
+    /**
+     * <p>Returns the value of the red component in the range defined by this
+     * color's color space (see {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}).</p>
+     *
+     * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB},
+     * calling this method is equivalent to <code>getComponent(0)</code>.</p>
+     *
+     * @see #alpha()
+     * @see #red()
+     * @see #green
+     * @see #getComponents()
+     */
+    public float red() {
+        return mComponents[0];
+    }
+
+    /**
+     * <p>Returns the value of the green component in the range defined by this
+     * color's color space (see {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}).</p>
+     *
+     * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB},
+     * calling this method is equivalent to <code>getComponent(1)</code>.</p>
+     *
+     * @see #alpha()
+     * @see #red()
+     * @see #green
+     * @see #getComponents()
+     */
+    public float green() {
+        return mComponents[1];
+    }
+
+    /**
+     * <p>Returns the value of the blue component in the range defined by this
+     * color's color space (see {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}).</p>
+     *
+     * <p>If this color's color model is not {@link ColorSpace.Model#RGB RGB},
+     * calling this method is equivalent to <code>getComponent(2)</code>.</p>
+     *
+     * @see #alpha()
+     * @see #red()
+     * @see #green
+     * @see #getComponents()
+     */
+    public float blue() {
+        return mComponents[2];
+    }
+
+    /**
+     * Returns the value of the alpha component in the range \([0..1]\).
+     * Calling this method is equivalent to
+     * <code>getComponent(getComponentCount())</code>.
+     *
+     * @see #red()
+     * @see #green()
+     * @see #blue()
+     * @see #getComponents()
+     * @see #getComponent(int)
+     */
+    public float alpha() {
+        return mComponents[mComponents.length - 1];
+    }
+
+    /**
+     * Returns this color's components as a new array. The last element of the
+     * array is always the alpha component.
+     *
+     * @return A new, non-null array whose size is equal to {@link #getComponentCount()}
+     *
+     * @see #getComponent(int)
+     */
+    @NonNull
+    @Size(min = 4, max = 5)
+    public float[] getComponents() {
+        return Arrays.copyOf(mComponents, mColorSpace.getComponentCount() + 1);
+    }
+
+    /**
+     * <p>Returns the value of the specified component in the range defined by
+     * this color's color space (see {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}).</p>
+     *
+     * <p>If the requested component index is {@link #getComponentCount()},
+     * this method returns the alpha component, always in the range
+     * \([0..1\).</p>
+     *
+     * @see #getComponents()
+     *
+     * @throws ArrayIndexOutOfBoundsException If the specified component index
+     * is < 0 or >= {@link #getComponentCount()}
+     */
+    public float getComponent(@IntRange(from = 0, to = 4) int component) {
+        return mComponents[component];
+    }
+
+    /**
+     * <p>Returns the relative luminance of this color.</p>
+     *
+     * <p>Based on the formula for relative luminance defined in WCAG 2.0,
+     * W3C Recommendation 11 December 2008.</p>
+     *
+     * @return A value between 0 (darkest black) and 1 (lightest white)
+     *
+     * @throws IllegalArgumentException If the this color's color space
+     * does not use the {@link ColorSpace.Model#RGB RGB} color model
+     */
+    public float luminance() {
+        if (mColorSpace.getModel() != ColorSpace.Model.RGB) {
+            throw new IllegalArgumentException("The specified color must be encoded in an RGB " +
+                    "color space. The supplied color space is " + mColorSpace.getModel());
+        }
+
+        DoubleUnaryOperator eotf = ((ColorSpace.Rgb) mColorSpace).getEotf();
+        double r = eotf.applyAsDouble(mComponents[0]);
+        double g = eotf.applyAsDouble(mComponents[1]);
+        double b = eotf.applyAsDouble(mComponents[2]);
+
+        return saturate((float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b)));
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Color color = (Color) o;
+
+        //noinspection SimplifiableIfStatement
+        if (!Arrays.equals(mComponents, color.mComponents)) return false;
+        return mColorSpace.equals(color.mColorSpace);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = Arrays.hashCode(mComponents);
+        result = 31 * result + mColorSpace.hashCode();
+        return result;
+    }
+
+    /**
+     * <p>Returns a string representation of the object. This method returns
+     * a string equal to the value of:</p>
+     *
+     * <pre class="prettyprint">
+     * "Color(" + r + ", " + g + ", " + b + ", " + a +
+     *         ", " + getColorSpace().getName + ')'
+     * </pre>
+     *
+     * <p>For instance, the string representation of opaque black in the sRGB
+     * color space is equal to the following value:</p>
+     *
+     * <pre>
+     * Color(0.0, 0.0, 0.0, 1.0, sRGB IEC61966-2.1)
+     * </pre>
+     *
+     * @return A non-null string representation of the object
+     */
+    @Override
+    @NonNull
+    public String toString() {
+        StringBuilder b = new StringBuilder("Color(");
+        for (float c : mComponents) {
+            b.append(c).append(", ");
+        }
+        b.append(mColorSpace.getName());
+        b.append(')');
+        return b.toString();
+    }
+
+    /**
+     * Returns the color space encoded in the specified color long.
+     *
+     * @param color The color long whose color space to extract
+     * @return A non-null color space instance. If the color long encodes
+     * an unknown or invalid color space, the {@link ColorSpace.Named#SRGB sRGB}
+     * color space is returned
+     *
+     * @see #red(long)
+     * @see #green(long)
+     * @see #blue(long)
+     * @see #alpha(long)
+     */
+    @NonNull
+    public static ColorSpace colorSpace(@ColorLong long color) {
+        return ColorSpace.get((int) (color & 0x3fL));
+    }
+
+    /**
+     * Returns the red component encoded in the specified color long.
+     * The range of the returned value depends on the color space
+     * associated with the specified color. The color space can be
+     * queried by calling {@link #colorSpace(long)}.
+     *
+     * @param color The color long whose red channel to extract
+     * @return A float value with a range defined by the specified color's
+     * color space
+     *
+     * @see #colorSpace(long)
+     * @see #green(long)
+     * @see #blue(long)
+     * @see #alpha(long)
+     */
+    public static float red(@ColorLong long color) {
+        if ((color & 0x3fL) == 0L) return ((color >> 48) & 0xff) / 255.0f;
+        return Half.toFloat((short) ((color >> 48) & 0xffff));
+    }
+
+    /**
+     * Returns the green component encoded in the specified color long.
+     * The range of the returned value depends on the color space
+     * associated with the specified color. The color space can be
+     * queried by calling {@link #colorSpace(long)}.
+     *
+     * @param color The color long whose green channel to extract
+     * @return A float value with a range defined by the specified color's
+     * color space
+     *
+     * @see #colorSpace(long)
+     * @see #red(long)
+     * @see #blue(long)
+     * @see #alpha(long)
+     */
+    public static float green(@ColorLong long color) {
+        if ((color & 0x3fL) == 0L) return ((color >> 40) & 0xff) / 255.0f;
+        return Half.toFloat((short) ((color >> 32) & 0xffff));
+    }
+
+    /**
+     * Returns the blue component encoded in the specified color long.
+     * The range of the returned value depends on the color space
+     * associated with the specified color. The color space can be
+     * queried by calling {@link #colorSpace(long)}.
+     *
+     * @param color The color long whose blue channel to extract
+     * @return A float value with a range defined by the specified color's
+     * color space
+     *
+     * @see #colorSpace(long)
+     * @see #red(long)
+     * @see #green(long)
+     * @see #alpha(long)
+     */
+    public static float blue(@ColorLong long color) {
+        if ((color & 0x3fL) == 0L) return ((color >> 32) & 0xff) / 255.0f;
+        return Half.toFloat((short) ((color >> 16) & 0xffff));
+    }
+
+    /**
+     * Returns the alpha component encoded in the specified color long.
+     * The returned value is always in the range \([0..1]\).
+     *
+     * @param color The color long whose blue channel to extract
+     * @return A float value in the range \([0..1]\)
+     *
+     * @see #colorSpace(long)
+     * @see #red(long)
+     * @see #green(long)
+     * @see #blue(long)
+     */
+    public static float alpha(@ColorLong long color) {
+        if ((color & 0x3fL) == 0L) return ((color >> 56) & 0xff) / 255.0f;
+        return ((color >> 6) & 0x3ff) / 1023.0f;
+    }
+
+    /**
+     * Indicates whether the specified color is in the
+     * {@link ColorSpace.Named#SRGB sRGB} color space.
+     *
+     * @param color The color to test
+     * @return True if the color is in the sRGB color space, false otherwise
+     *
+     * @see #isInColorSpace(long, ColorSpace)
+     * @see #isWideGamut(long)
+     */
+    public static boolean isSrgb(@ColorLong long color) {
+        return colorSpace(color).isSrgb();
+    }
+
+    /**
+     * Indicates whether the specified color is in a wide-gamut color space.
+     * See {@link ColorSpace#isWideGamut()} for a definition of a wide-gamut
+     * color space.
+     *
+     * @param color The color to test
+     * @return True if the color is in a wide-gamut color space, false otherwise
+     *
+     * @see #isInColorSpace(long, ColorSpace)
+     * @see #isSrgb(long)
+     * @see ColorSpace#isWideGamut()
+     */
+    public static boolean isWideGamut(@ColorLong long color) {
+        return colorSpace(color).isWideGamut();
+    }
+
+    /**
+     * Indicates whether the specified color is in the specified color space.
+     *
+     * @param color The color to test
+     * @param colorSpace The color space to test against
+     * @return True if the color is in the specified color space, false otherwise
+     *
+     * @see #isSrgb(long)
+     * @see #isWideGamut(long)
+     */
+    public static boolean isInColorSpace(@ColorLong long color, @NonNull ColorSpace colorSpace) {
+        return (int) (color & 0x3fL) == colorSpace.getId();
+    }
+
+    /**
+     * Converts the specified color long to an ARGB color int. A color int is
+     * always in the {@link ColorSpace.Named#SRGB sRGB} color space. This implies
+     * a color space conversion is applied if needed.
+     *
+     * @return An ARGB color in the sRGB color space
+     */
+    @ColorInt
+    public static int toArgb(@ColorLong long color) {
+        if ((color & 0x3fL) == 0L) return (int) (color >> 32);
+
+        float r = red(color);
+        float g = green(color);
+        float b = blue(color);
+        float a = alpha(color);
+
+        // The transformation saturates the output
+        float[] c = ColorSpace.connect(colorSpace(color)).transform(r, g, b);
+
+        return ((int) (a    * 255.0f + 0.5f) << 24) |
+               ((int) (c[0] * 255.0f + 0.5f) << 16) |
+               ((int) (c[1] * 255.0f + 0.5f) <<  8) |
+                (int) (c[2] * 255.0f + 0.5f);
+    }
+
+    /**
+     * Creates a new <code>Color</code> instance from an ARGB color int.
+     * The resulting color is in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space.
+     *
+     * @param color The ARGB color int to create a <code>Color</code> from
+     * @return A non-null instance of {@link Color}
+     */
+    @NonNull
+    public static Color valueOf(@ColorInt int color) {
+        float r = ((color >> 16) & 0xff) / 255.0f;
+        float g = ((color >>  8) & 0xff) / 255.0f;
+        float b = ((color      ) & 0xff) / 255.0f;
+        float a = ((color >> 24) & 0xff) / 255.0f;
+        return new Color(r, g, b, a, ColorSpace.get(ColorSpace.Named.SRGB));
+    }
+
+    /**
+     * Creates a new <code>Color</code> instance from a color long.
+     * The resulting color is in the same color space as the specified color long.
+     *
+     * @param color The color long to create a <code>Color</code> from
+     * @return A non-null instance of {@link Color}
+     */
+    @NonNull
+    public static Color valueOf(@ColorLong long color) {
+        return new Color(red(color), green(color), blue(color), alpha(color), colorSpace(color));
+    }
+
+    /**
+     * Creates a new opaque <code>Color</code> in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space with the specified red, green and blue component values. The component
+     * values must be in the range \([0..1]\).
+     *
+     * @param r The red component of the opaque sRGB color to create, in \([0..1]\)
+     * @param g The green component of the opaque sRGB color to create, in \([0..1]\)
+     * @param b The blue component of the opaque sRGB color to create, in \([0..1]\)
+     * @return A non-null instance of {@link Color}
+     */
+    @NonNull
+    public static Color valueOf(float r, float g, float b) {
+        return new Color(r, g, b, 1.0f);
+    }
+
+    /**
+     * Creates a new <code>Color</code> in the {@link ColorSpace.Named#SRGB sRGB}
+     * color space with the specified red, green, blue and alpha component values.
+     * The component values must be in the range \([0..1]\).
+     *
+     * @param r The red component of the sRGB color to create, in \([0..1]\)
+     * @param g The green component of the sRGB color to create, in \([0..1]\)
+     * @param b The blue component of the sRGB color to create, in \([0..1]\)
+     * @param a The alpha component of the sRGB color to create, in \([0..1]\)
+     * @return A non-null instance of {@link Color}
+     */
+    @NonNull
+    public static Color valueOf(float r, float g, float b, float a) {
+        return new Color(saturate(r), saturate(g), saturate(b), saturate(a));
+    }
+
+    /**
+     * Creates a new <code>Color</code> in the specified color space with the
+     * specified red, green, blue and alpha component values. The range of the
+     * components is defined by {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}. The values passed to this method
+     * must be in the proper range.
+     *
+     * @param r The red component of the color to create
+     * @param g The green component of the color to create
+     * @param b The blue component of the color to create
+     * @param a The alpha component of the color to create, in \([0..1]\)
+     * @param colorSpace The color space of the color to create
+     * @return A non-null instance of {@link Color}
+     *
+     * @throws IllegalArgumentException If the specified color space uses a
+     * color model with more than 3 components
+     */
+    @NonNull
+    public static Color valueOf(float r, float g, float b, float a, @NonNull ColorSpace colorSpace) {
+        if (colorSpace.getComponentCount() > 3) {
+            throw new IllegalArgumentException("The specified color space must use a color model " +
+                    "with at most 3 color components");
+        }
+        return new Color(r, g, b, a, colorSpace);
+    }
+
+    /**
+     * <p>Creates a new <code>Color</code> in the specified color space with the
+     * specified component values. The range of the components is defined by
+     * {@link ColorSpace#getMinValue(int)} and {@link ColorSpace#getMaxValue(int)}.
+     * The values passed to this method must be in the proper range. The alpha
+     * component is always in the range \([0..1]\).</p>
+     *
+     * <p>The length of the array of components must be at least
+     * <code>{@link ColorSpace#getComponentCount()} + 1</code>. The component at index
+     * {@link ColorSpace#getComponentCount()} is always alpha.</p>
+     *
+     * @param components The components of the color to create, with alpha as the last component
+     * @param colorSpace The color space of the color to create
+     * @return A non-null instance of {@link Color}
+     *
+     * @throws IllegalArgumentException If the array of components is smaller than
+     * required by the color space
+     */
+    @NonNull
+    public static Color valueOf(@NonNull @Size(min = 4, max = 5) float[] components,
+            @NonNull ColorSpace colorSpace) {
+        if (components.length < colorSpace.getComponentCount() + 1) {
+            throw new IllegalArgumentException("Received a component array of length " +
+                    components.length + " but the color model requires " +
+                    (colorSpace.getComponentCount() + 1) + " (including alpha)");
+        }
+        return new Color(Arrays.copyOf(components, colorSpace.getComponentCount() + 1), colorSpace);
+    }
+
+    /**
+     * Converts the specified ARGB color int to an RGBA color long in the sRGB
+     * color space. See the documentation of this class for a description of
+     * the color long format.
+     *
+     * @param color The ARGB color int to convert to an RGBA color long in sRGB
+     *
+     * @return A color long
+     */
+    @ColorLong
+    public static long pack(@ColorInt int color) {
+        return (color & 0xffffffffL) << 32;
+    }
+
+    /**
+     * Packs the sRGB color defined by the specified red, green and blue component
+     * values into an RGBA color long in the sRGB color space. The alpha component
+     * is set to 1.0. See the documentation of this class for a description of the
+     * color long format.
+     *
+     * @param red The red component of the sRGB color to create, in \([0..1]\)
+     * @param green The green component of the sRGB color to create, in \([0..1]\)
+     * @param blue The blue component of the sRGB color to create, in \([0..1]\)
+     *
+     * @return A color long
+     */
+    @ColorLong
+    public static long pack(float red, float green, float blue) {
+        return pack(red, green, blue, 1.0f, ColorSpace.get(ColorSpace.Named.SRGB));
+    }
+
+    /**
+     * Packs the sRGB color defined by the specified red, green, blue and alpha
+     * component values into an RGBA color long in the sRGB color space. See the
+     * documentation of this class for a description of the color long format.
+     *
+     * @param red The red component of the sRGB color to create, in \([0..1]\)
+     * @param green The green component of the sRGB color to create, in \([0..1]\)
+     * @param blue The blue component of the sRGB color to create, in \([0..1]\)
+     * @param alpha The alpha component of the sRGB color to create, in \([0..1]\)
+     *
+     * @return A color long
+     */
+    @ColorLong
+    public static long pack(float red, float green, float blue, float alpha) {
+        return pack(red, green, blue, alpha, ColorSpace.get(ColorSpace.Named.SRGB));
+    }
+
+    /**
+     * <p>Packs the 3 component color defined by the specified red, green, blue and
+     * alpha component values into a color long in the specified color space. See the
+     * documentation of this class for a description of the color long format.</p>
+     *
+     * <p>The red, green and blue components must be in the range defined by the
+     * specified color space. See {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}.</p>
+     *
+     * @param red The red component of the color to create
+     * @param green The green component of the color to create
+     * @param blue The blue component of the color to create
+     * @param alpha The alpha component of the color to create, in \([0..1]\)
+     *
+     * @return A color long
+     *
+     * @throws IllegalArgumentException If the color space's id is {@link ColorSpace#MIN_ID}
+     * or if the color space's color model has more than 3 components
+     */
+    @ColorLong
+    public static long pack(float red, float green, float blue, float alpha,
+            @NonNull ColorSpace colorSpace) {
+        if (colorSpace.isSrgb()) {
+            int argb =
+                    ((int) (alpha * 255.0f + 0.5f) << 24) |
+                    ((int) (red   * 255.0f + 0.5f) << 16) |
+                    ((int) (green * 255.0f + 0.5f) <<  8) |
+                     (int) (blue  * 255.0f + 0.5f);
+            return (argb & 0xffffffffL) << 32;
+        }
+
+        int id = colorSpace.getId();
+        if (id == ColorSpace.MIN_ID) {
+            throw new IllegalArgumentException(
+                    "Unknown color space, please use a color space returned by ColorSpace.get()");
+        }
+        if (colorSpace.getComponentCount() > 3) {
+            throw new IllegalArgumentException(
+                    "The color space must use a color model with at most 3 components");
+        }
+
+        @HalfFloat short r = Half.valueOf(red);
+        @HalfFloat short g = Half.valueOf(green);
+        @HalfFloat short b = Half.valueOf(blue);
+
+        int a = (int) (Math.max(0.0f, Math.min(alpha, 1.0f)) * 1023.0f + 0.5f);
+
+        // Suppress sign extension
+        return  (r & 0xffffL) << 48 |
+                (g & 0xffffL) << 32 |
+                (b & 0xffffL) << 16 |
+                (a & 0x3ffL ) <<  6 |
+                id & 0x3fL;
+    }
+
+    /**
+     * Converts the specified ARGB color int from the {@link ColorSpace.Named#SRGB sRGB}
+     * color space into the specified destination color space. The resulting color is
+     * returned as a color long. See the documentation of this class for a description
+     * of the color long format.
+     *
+     * @param color The sRGB color int to convert
+     * @param colorSpace The destination color space
+     * @return A color long in the destination color space
+     */
+    @ColorLong
+    public static long convert(@ColorInt int color, @NonNull ColorSpace colorSpace) {
+        float r = ((color >> 16) & 0xff) / 255.0f;
+        float g = ((color >>  8) & 0xff) / 255.0f;
+        float b = ((color      ) & 0xff) / 255.0f;
+        float a = ((color >> 24) & 0xff) / 255.0f;
+        ColorSpace source = ColorSpace.get(ColorSpace.Named.SRGB);
+        return convert(r, g, b, a, source, colorSpace);
+    }
+
+    /**
+     * <p>Converts the specified color long from its color space into the specified
+     * destination color space. The resulting color is returned as a color long. See
+     * the documentation of this class for a description of the color long format.</p>
+     *
+     * <p>When converting several colors in a row, it is recommended to use
+     * {@link #convert(long, ColorSpace.Connector)} instead to
+     * avoid the creation of a {@link ColorSpace.Connector} on every invocation.</p>
+     *
+     * @param color The color long to convert
+     * @param colorSpace The destination color space
+     * @return A color long in the destination color space
+     */
+    @ColorLong
+    public static long convert(@ColorLong long color, @NonNull ColorSpace colorSpace) {
+        float r = red(color);
+        float g = green(color);
+        float b = blue(color);
+        float a = alpha(color);
+        ColorSpace source = colorSpace(color);
+        return convert(r, g, b, a, source, colorSpace);
+    }
+
+    /**
+     * <p>Converts the specified 3 component color from the source color space to the
+     * destination color space. The resulting color is returned as a color long. See
+     * the documentation of this class for a description of the color long format.</p>
+     *
+     * <p>When converting multiple colors in a row, it is recommended to use
+     * {@link #convert(float, float, float, float, ColorSpace.Connector)} instead to
+     * avoid the creation of a {@link ColorSpace.Connector} on every invocation.</p>
+     *
+     * <p>The red, green and blue components must be in the range defined by the
+     * specified color space. See {@link ColorSpace#getMinValue(int)} and
+     * {@link ColorSpace#getMaxValue(int)}.</p>
+     *
+     * @param r The red component of the color to convert
+     * @param g The green component of the color to convert
+     * @param b The blue component of the color to convert
+     * @param a The alpha component of the color to convert, in \([0..1]\)
+     * @param source The source color space, cannot be null
+     * @param destination The destination color space, cannot be null
+     * @return A color long in the destination color space
+     *
+     * @see #convert(float, float, float, float, ColorSpace.Connector)
+     */
+    @ColorLong
+    public static long convert(float r, float g, float b, float a,
+            @NonNull ColorSpace source, @NonNull ColorSpace destination) {
+        float[] c = ColorSpace.connect(source, destination).transform(r, g, b);
+        return pack(c[0], c[1], c[2], a, destination);
+    }
+
+    /**
+     * <p>Converts the specified color long from a color space to another using the
+     * specified color space {@link ColorSpace.Connector connector}. The resulting
+     * color is returned as a color long. See the documentation of this class for a
+     * description of the color long format.</p>
+     *
+     * <p>When converting several colors in a row, this method is preferable to
+     * {@link #convert(long, ColorSpace)} as it prevents a new connector from being
+     * created on every invocation.</p>
+     *
+     * <p class="note">The connector's source color space should match the color long's
+     * color space.</p>
+     *
+     * @param color The color long to convert
+     * @param connector A color space connector, cannot be null
+     * @return A color long in the destination color space of the connector
+     */
+    @ColorLong
+    public static long convert(@ColorLong long color, @NonNull ColorSpace.Connector connector) {
+        float r = red(color);
+        float g = green(color);
+        float b = blue(color);
+        float a = alpha(color);
+        return convert(r, g, b, a, connector);
+    }
+
+    /**
+     * <p>Converts the specified 3 component color from a color space to another using
+     * the specified color space {@link ColorSpace.Connector connector}. The resulting
+     * color is returned as a color long. See the documentation of this class for a
+     * description of the color long format.</p>
+     *
+     * <p>When converting several colors in a row, this method is preferable to
+     * {@link #convert(float, float, float, float, ColorSpace, ColorSpace)} as
+     * it prevents a new connector from being created on every invocation.</p>
+     *
+     * <p>The red, green and blue components must be in the range defined by the
+     * source color space of the connector. See {@link ColorSpace#getMinValue(int)}
+     * and {@link ColorSpace#getMaxValue(int)}.</p>
+     *
+     * @param r The red component of the color to convert
+     * @param g The green component of the color to convert
+     * @param b The blue component of the color to convert
+     * @param a The alpha component of the color to convert, in \([0..1]\)
+     * @param connector A color space connector, cannot be null
+     * @return A color long in the destination color space of the connector
+     *
+     * @see #convert(float, float, float, float, ColorSpace, ColorSpace)
+     */
+    @ColorLong
+    public static long convert(float r, float g, float b, float a,
+            @NonNull ColorSpace.Connector connector) {
+        float[] c = connector.transform(r, g, b);
+        return pack(c[0], c[1], c[2], a, connector.getDestination());
+    }
+
+    /**
+     * <p>Returns the relative luminance of a color.</p>
+     *
+     * <p>Based on the formula for relative luminance defined in WCAG 2.0,
+     * W3C Recommendation 11 December 2008.</p>
+     *
+     * @return A value between 0 (darkest black) and 1 (lightest white)
+     *
+     * @throws IllegalArgumentException If the specified color's color space
+     * does not use the {@link ColorSpace.Model#RGB RGB} color model
+     */
+    public static float luminance(@ColorLong long color) {
+        ColorSpace colorSpace = colorSpace(color);
+        if (colorSpace.getModel() != ColorSpace.Model.RGB) {
+            throw new IllegalArgumentException("The specified color must be encoded in an RGB " +
+                    "color space. The supplied color space is " + colorSpace.getModel());
+        }
+
+        DoubleUnaryOperator eotf = ((ColorSpace.Rgb) colorSpace).getEotf();
+        double r = eotf.applyAsDouble(red(color));
+        double g = eotf.applyAsDouble(green(color));
+        double b = eotf.applyAsDouble(blue(color));
+
+        return saturate((float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b)));
+    }
+
+    private static float saturate(float v) {
+        return v <= 0.0f ? 0.0f : (v >= 1.0f ? 1.0f : v);
+    }
+
     /**
      * Return the alpha component of a color int. This is the same as saying
      * color >>> 24
      */
+    @IntRange(from = 0, to = 255)
     public static int alpha(int color) {
         return color >>> 24;
     }
@@ -63,6 +1209,7 @@
      * Return the red component of a color int. This is the same as saying
      * (color >> 16) & 0xFF
      */
+    @IntRange(from = 0, to = 255)
     public static int red(int color) {
         return (color >> 16) & 0xFF;
     }
@@ -71,6 +1218,7 @@
      * Return the green component of a color int. This is the same as saying
      * (color >> 8) & 0xFF
      */
+    @IntRange(from = 0, to = 255)
     public static int green(int color) {
         return (color >> 8) & 0xFF;
     }
@@ -79,41 +1227,86 @@
      * Return the blue component of a color int. This is the same as saying
      * color & 0xFF
      */
+    @IntRange(from = 0, to = 255)
     public static int blue(int color) {
         return color & 0xFF;
     }
 
     /**
      * Return a color-int from red, green, blue components.
-     * The alpha component is implicity 255 (fully opaque).
-     * These component values should be [0..255], but there is no
+     * The alpha component is implicitly 255 (fully opaque).
+     * These component values should be \([0..255]\), but there is no
      * range check performed, so if they are out of range, the
      * returned color is undefined.
-     * @param red  Red component [0..255] of the color
-     * @param green Green component [0..255] of the color
-     * @param blue  Blue component [0..255] of the color
+     *
+     * @param red  Red component \([0..255]\) of the color
+     * @param green Green component \([0..255]\) of the color
+     * @param blue  Blue component \([0..255]\) of the color
      */
     @ColorInt
-    public static int rgb(int red, int green, int blue) {
+    public static int rgb(
+            @IntRange(from = 0, to = 255) int red,
+            @IntRange(from = 0, to = 255) int green,
+            @IntRange(from = 0, to = 255) int blue) {
         return 0xff000000 | (red << 16) | (green << 8) | blue;
     }
 
     /**
-     * Return a color-int from alpha, red, green, blue components.
-     * These component values should be [0..255], but there is no
-     * range check performed, so if they are out of range, the
+     * Return a color-int from red, green, blue float components
+     * in the range \([0..1]\). The alpha component is implicitly
+     * 1.0 (fully opaque). If the components are out of range, the
      * returned color is undefined.
-     * @param alpha Alpha component [0..255] of the color
-     * @param red   Red component [0..255] of the color
-     * @param green Green component [0..255] of the color
-     * @param blue  Blue component [0..255] of the color
+     *
+     * @param red Red component \([0..1]\) of the color
+     * @param green Green component \([0..1]\) of the color
+     * @param blue Blue component \([0..1]\) of the color
      */
     @ColorInt
-    public static int argb(int alpha, int red, int green, int blue) {
+    public static int rgb(float red, float green, float blue) {
+        return 0xff000000 |
+               ((int) (red   * 255.0f + 0.5f) << 16) |
+               ((int) (green * 255.0f + 0.5f) <<  8) |
+                (int) (blue  * 255.0f + 0.5f);
+    }
+
+    /**
+     * Return a color-int from alpha, red, green, blue components.
+     * These component values should be \([0..255]\), but there is no
+     * range check performed, so if they are out of range, the
+     * returned color is undefined.
+     * @param alpha Alpha component \([0..255]\) of the color
+     * @param red Red component \([0..255]\) of the color
+     * @param green Green component \([0..255]\) of the color
+     * @param blue Blue component \([0..255]\) of the color
+     */
+    @ColorInt
+    public static int argb(
+            @IntRange(from = 0, to = 255) int alpha,
+            @IntRange(from = 0, to = 255) int red,
+            @IntRange(from = 0, to = 255) int green,
+            @IntRange(from = 0, to = 255) int blue) {
         return (alpha << 24) | (red << 16) | (green << 8) | blue;
     }
 
     /**
+     * Return a color-int from alpha, red, green, blue float components
+     * in the range \([0..1]\). If the components are out of range, the
+     * returned color is undefined.
+     *
+     * @param alpha Alpha component \([0..1]\) of the color
+     * @param red Red component \([0..1]\) of the color
+     * @param green Green component \([0..1]\) of the color
+     * @param blue Blue component \([0..1]\) of the color
+     */
+    @ColorInt
+    public static int argb(float alpha, float red, float green, float blue) {
+        return ((int) (alpha * 255.0f + 0.5f) << 24) |
+               ((int) (red   * 255.0f + 0.5f) << 16) |
+               ((int) (green * 255.0f + 0.5f) <<  8) |
+                (int) (blue  * 255.0f + 0.5f);
+    }
+
+    /**
      * Returns the relative luminance of a color.
      * <p>
      * Assumes sRGB encoding. Based on the formula for relative luminance
@@ -124,23 +1317,31 @@
     public static float luminance(@ColorInt int color) {
         ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
         DoubleUnaryOperator eotf = cs.getEotf();
-        double red = eotf.applyAsDouble(Color.red(color) / 255.0);
-        double green = eotf.applyAsDouble(Color.green(color) / 255.0);
-        double blue = eotf.applyAsDouble(Color.blue(color) / 255.0);
-        return (float) ((0.2126 * red) + (0.7152 * green) + (0.0722 * blue));
+
+        double r = eotf.applyAsDouble(red(color) / 255.0);
+        double g = eotf.applyAsDouble(green(color) / 255.0);
+        double b = eotf.applyAsDouble(blue(color) / 255.0);
+
+        return (float) ((0.2126 * r) + (0.7152 * g) + (0.0722 * b));
     }
 
     /**
-     * Parse the color string, and return the corresponding color-int.
+     * </p>Parse the color string, and return the corresponding color-int.
      * If the string cannot be parsed, throws an IllegalArgumentException
-     * exception. Supported formats are:
-     * #RRGGBB
-     * #AARRGGBB
-     * or one of the following names:
-     * 'red', 'blue', 'green', 'black', 'white', 'gray', 'cyan', 'magenta',
-     * 'yellow', 'lightgray', 'darkgray', 'grey', 'lightgrey', 'darkgrey',
-     * 'aqua', 'fuchsia', 'lime', 'maroon', 'navy', 'olive', 'purple',
-     * 'silver', 'teal'.
+     * exception. Supported formats are:</p>
+     *
+     * <ul>
+     *   <li><code>#RRGGBB</code></li>
+     *   <li><code>#AARRGGBB</code></li>
+     * </ul>
+     *
+     * <p>The following names are also accepted: <code>red</code>, <code>blue</code>,
+     * <code>green</code>, <code>black</code>, <code>white</code>, <code>gray</code>,
+     * <code>cyan</code>, <code>magenta</code>, <code>yellow</code>, <code>lightgray</code>,
+     * <code>darkgray</code>, <code>grey</code>, <code>lightgrey</code>, <code>darkgrey</code>,
+     * <code>aqua</code>, <code>fuchsia</code>, <code>lime</code>, <code>maroon</code>,
+     * <code>navy</code>, <code>olive</code>, <code>purple</code>, <code>silver</code>,
+     * and <code>teal</code>.</p>
      */
     @ColorInt
     public static int parseColor(@Size(min=1) String colorString) {
@@ -165,15 +1366,20 @@
 
     /**
      * Convert RGB components to HSV.
-     *     hsv[0] is Hue [0 .. 360)
-     *     hsv[1] is Saturation [0...1]
-     *     hsv[2] is Value [0...1]
-     * @param red  red component value [0..255]
-     * @param green  green component value [0..255]
-     * @param blue  blue component value [0..255]
+     * <ul>
+     *   <li><code>hsv[0]</code> is Hue \([0..360[\)</li>
+     *   <li><code>hsv[1]</code> is Saturation \([0...1]\)</li>
+     *   <li><code>hsv[2]</code> is Value \([0...1]\)</li>
+     * </ul>
+     * @param red  red component value \([0..255]\)
+     * @param green  green component value \([0..255]\)
+     * @param blue  blue component value \([0..255]\)
      * @param hsv  3 element array which holds the resulting HSV components.
      */
-    public static void RGBToHSV(int red, int green, int blue, @Size(3) float hsv[]) {
+    public static void RGBToHSV(
+            @IntRange(from = 0, to = 255) int red,
+            @IntRange(from = 0, to = 255) int green,
+            @IntRange(from = 0, to = 255) int blue, @Size(3) float hsv[]) {
         if (hsv.length < 3) {
             throw new RuntimeException("3 components required for hsv");
         }
@@ -181,10 +1387,12 @@
     }
 
     /**
-     * Convert the argb color to its HSV components.
-     *     hsv[0] is Hue [0 .. 360)
-     *     hsv[1] is Saturation [0...1]
-     *     hsv[2] is Value [0...1]
+     * Convert the ARGB color to its HSV components.
+     * <ul>
+     *   <li><code>hsv[0]</code> is Hue \([0..360[\)</li>
+     *   <li><code>hsv[1]</code> is Saturation \([0...1]\)</li>
+     *   <li><code>hsv[2]</code> is Value \([0...1]\)</li>
+     * </ul>
      * @param color the argb color to convert. The alpha component is ignored.
      * @param hsv  3 element array which holds the resulting HSV components.
      */
@@ -194,13 +1402,16 @@
 
     /**
      * Convert HSV components to an ARGB color. Alpha set to 0xFF.
-     *     hsv[0] is Hue [0 .. 360)
-     *     hsv[1] is Saturation [0...1]
-     *     hsv[2] is Value [0...1]
+     * <ul>
+     *   <li><code>hsv[0]</code> is Hue \([0..360[\)</li>
+     *   <li><code>hsv[1]</code> is Saturation \([0...1]\)</li>
+     *   <li><code>hsv[2]</code> is Value \([0...1]\)</li>
+     * </ul>
      * If hsv values are out of range, they are pinned.
      * @param hsv  3 element array which holds the input HSV components.
      * @return the resulting argb color
     */
+    @ColorInt
     public static int HSVToColor(@Size(3) float hsv[]) {
         return HSVToColor(0xFF, hsv);
     }
@@ -208,15 +1419,18 @@
     /**
      * Convert HSV components to an ARGB color. The alpha component is passed
      * through unchanged.
-     *     hsv[0] is Hue [0 .. 360)
-     *     hsv[1] is Saturation [0...1]
-     *     hsv[2] is Value [0...1]
+     * <ul>
+     *   <li><code>hsv[0]</code> is Hue \([0..360[\)</li>
+     *   <li><code>hsv[1]</code> is Saturation \([0...1]\)</li>
+     *   <li><code>hsv[2]</code> is Value \([0...1]\)</li>
+     * </ul>
      * If hsv values are out of range, they are pinned.
      * @param alpha the alpha component of the returned argb color.
      * @param hsv  3 element array which holds the input HSV components.
      * @return the resulting argb color
-    */
-    public static int HSVToColor(int alpha, @Size(3) float hsv[]) {
+     */
+    @ColorInt
+    public static int HSVToColor(@IntRange(from = 0, to = 255) int alpha, @Size(3) float hsv[]) {
         if (hsv.length < 3) {
             throw new RuntimeException("3 components required for hsv");
         }
@@ -236,7 +1450,7 @@
      * @hide
      */
     @ColorInt
-    public static int getHtmlColor(String color) {
+    public static int getHtmlColor(@NonNull String color) {
         Integer i = sColorNameMap.get(color.toLowerCase(Locale.ROOT));
         if (i != null) {
             return i;
diff --git a/graphics/java/android/graphics/ColorSpace.java b/graphics/java/android/graphics/ColorSpace.java
index d968516..ec00c45 100644
--- a/graphics/java/android/graphics/ColorSpace.java
+++ b/graphics/java/android/graphics/ColorSpace.java
@@ -16,6 +16,7 @@
 
 package android.graphics;
 
+import android.annotation.AnyThread;
 import android.annotation.ColorInt;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
@@ -126,7 +127,8 @@
  *
  * <p>To visualize and debug color spaces, you can call {@link #createRenderer()}.
  * The {@link Renderer} created by calling this method can be used to compare
- * color spaces and locate specific colors on a CIE 1931 chromaticity diagram.</p>
+ * color spaces and locate specific colors on a CIE 1931 or CIE 1976 UCS
+ * chromaticity diagram.</p>
  *
  * <p>The following code snippet shows how to render a bitmap that compares
  * the color gamuts and white points of {@link Named#DCI_P3} and
@@ -155,6 +157,7 @@
  * @see Adaptation
  * @see Renderer
  */
+@AnyThread
 @SuppressWarnings("StaticInitializerReferencesSubClass")
 public abstract class ColorSpace {
     /**
@@ -216,7 +219,7 @@
      *
      * @see #getId()
      */
-    public static final int MAX_ID = 64; // Do not change, used to encode in longs
+    public static final int MAX_ID = 63; // Do not change, used to encode in longs
 
     private static final float[] SRGB_PRIMARIES = { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f };
     private static final float[] NTSC_1953_PRIMARIES = { 0.67f, 0.33f, 0.21f, 0.71f, 0.14f, 0.08f };
@@ -341,11 +344,11 @@
          *             \end{equation}\)
          *         </td>
          *     </tr>
-         *     <tr><td>Range</td><td colspan="4">\([-0.5..7.5[\)</td></tr>
+         *     <tr><td>Range</td><td colspan="4">\([-0.799..2.399[\)</td></tr>
          * </table>
          * <p>
          *     <img src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" />
-         *     <figcaption style="text-align: center;">Extended RGB (orange) vs sRGB (white)</figcaption>
+         *     <figcaption style="text-align: center;">Extended sRGB (orange) vs sRGB (white)</figcaption>
          * </p>
          */
         EXTENDED_SRGB,
@@ -368,11 +371,11 @@
          *         <td>Electro-optical transfer function</td>
          *         <td colspan="4">\(C_{linear} = C_{scRGB}\)</td>
          *     </tr>
-         *     <tr><td>Range</td><td colspan="4">\([-0.5..7.5[\)</td></tr>
+         *     <tr><td>Range</td><td colspan="4">\([-0.5..7.499[\)</td></tr>
          * </table>
          * <p>
          *     <img src="{@docRoot}reference/android/images/graphics/colorspace_scrgb.png" />
-         *     <figcaption style="text-align: center;">Extended RGB (orange) vs sRGB (white)</figcaption>
+         *     <figcaption style="text-align: center;">Extended sRGB (orange) vs sRGB (white)</figcaption>
          * </p>
          */
         LINEAR_EXTENDED_SRGB,
@@ -1090,7 +1093,7 @@
      * space's color model. The resulting value is passed back in the specified
      * array.</p>
      *
-     * <p class="note>The specified array's length  must be at least equal to
+     * <p class="note">The specified array's length  must be at least equal to
      * to the number of color components as returned by
      * {@link Model#getComponentCount()}, and its first 3 values must
      * be the XYZ components to convert from.</p>
@@ -1125,6 +1128,7 @@
      * @return A string representation of the object
      */
     @Override
+    @NonNull
     public String toString() {
         return mName + " (id=" + mId + ", model=" + mModel + ")";
     }
@@ -1403,7 +1407,7 @@
                 ILLUMINANT_D65,
                 x -> absRcpResponse(x, 2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045),
                 x -> absResponse(x, 2.4, 1 / 1.055, 0.055 / 1.055, 1 / 12.92, 0.04045),
-                -0.5f, 7.5f,
+                -0.799f, 2.399f,
                 Named.EXTENDED_SRGB.ordinal()
         );
         sNamedColorSpaces[Named.LINEAR_EXTENDED_SRGB.ordinal()] = new ColorSpace.Rgb(
@@ -1412,7 +1416,7 @@
                 ILLUMINANT_D65,
                 DoubleUnaryOperator.identity(),
                 DoubleUnaryOperator.identity(),
-                -0.5f, 7.5f,
+                -0.5f, 7.499f,
                 Named.LINEAR_EXTENDED_SRGB.ordinal()
         );
         sNamedColorSpaces[Named.BT709.ordinal()] = new ColorSpace.Rgb(
@@ -1437,8 +1441,8 @@
                 "SMPTE RP 431-2-2007 DCI (P3)",
                 new float[] { 0.680f, 0.320f, 0.265f, 0.690f, 0.150f, 0.060f },
                 new float[] { 0.314f, 0.351f },
-                x -> Math.pow(x, 1 / 2.6),
-                x -> Math.pow(x, 2.6),
+                x -> Math.pow(x < 0.0f ? 0.0f : x, 1 / 2.6),
+                x -> Math.pow(x < 0.0f ? 0.0f : x, 2.6),
                 0.0f, 1.0f,
                 Named.DCI_P3.ordinal()
         );
@@ -1473,8 +1477,8 @@
                 "Adobe RGB (1998)",
                 new float[] { 0.64f, 0.33f, 0.21f, 0.71f, 0.15f, 0.06f },
                 ILLUMINANT_D65,
-                x -> Math.pow(x, 1 / 2.2),
-                x -> Math.pow(x, 2.2),
+                x -> Math.pow(x < 0.0f ? 0.0f : x, 1 / 2.2),
+                x -> Math.pow(x < 0.0f ? 0.0f : x, 2.2),
                 0.0f, 1.0f,
                 Named.ADOBE_RGB.ordinal()
         );
@@ -1720,6 +1724,7 @@
     /**
      * Implementation of the CIE XYZ color space. Assumes the white point is D50.
      */
+    @AnyThread
     private static final class Xyz extends ColorSpace {
         private Xyz(@NonNull String name, @IntRange(from = MIN_ID, to = MAX_ID) int id) {
             super(name, Model.XYZ, id);
@@ -1765,6 +1770,7 @@
      * Implementation of the CIE L*a*b* color space. Its PCS is CIE XYZ
      * with a white point of D50.
      */
+    @AnyThread
     private static final class Lab extends ColorSpace {
         private static final float A = 216.0f / 24389.0f;
         private static final float B = 841.0f / 108.0f;
@@ -1949,6 +1955,7 @@
      * <p>To learn more about the white point adaptation process, refer to the
      * documentation of {@link Adaptation}.</p>
      */
+    @AnyThread
     public static class Rgb extends ColorSpace {
         @NonNull private final float[] mWhitePoint;
         @NonNull private final float[] mPrimaries;
@@ -2337,7 +2344,7 @@
          * to "gamma space" (gamma encoded). The terms gamma space and gamma encoded
          * are frequently used because many OETFs can be closely approximated using
          * a simple power function of the form \(x^{\frac{1}{\gamma}}\) (the
-         * approximation of the {@link Named#SRGB sRGB} EOTF uses \(\gamma=2.2\)
+         * approximation of the {@link Named#SRGB sRGB} OETF uses \(\gamma=2.2\)
          * for instance).</p>
          *
          * @return A transfer function that converts from linear space to "gamma space"
@@ -2346,7 +2353,7 @@
          */
         @NonNull
         public DoubleUnaryOperator getOetf() {
-            return mOetf;
+            return mClampedOetf;
         }
 
         /**
@@ -2369,7 +2376,7 @@
          */
         @NonNull
         public DoubleUnaryOperator getEotf() {
-            return mEotf;
+            return mClampedEotf;
         }
 
         @Override
@@ -2924,6 +2931,7 @@
      * @see ColorSpace#connect(ColorSpace, RenderIntent)
      * @see ColorSpace#connect(ColorSpace)
      */
+    @AnyThread
     public static class Connector {
         @NonNull private final ColorSpace mSource;
         @NonNull private final ColorSpace mDestination;
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index 08a68f4..36fc596 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -22,8 +22,8 @@
 public class ComposeShader extends Shader {
 
     private int mPorterDuffMode;
-    private final Shader mShaderA;
-    private final Shader mShaderB;
+    final Shader mShaderA;
+    final Shader mShaderB;
 
     /** Create a new compose shader, given shaders A, B, and a combining mode.
         When the mode is applied, it will be given the result from shader A as its
diff --git a/graphics/tests/graphicstests/Android.mk b/graphics/tests/graphicstests/Android.mk
index 1845395..8ea44bd 100644
--- a/graphics/tests/graphicstests/Android.mk
+++ b/graphics/tests/graphicstests/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := FrameworksGraphicsTests
 
 include $(BUILD_PACKAGE)
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
index 35388d7..a740b13 100644
--- a/keystore/tests/Android.mk
+++ b/keystore/tests/Android.mk
@@ -6,6 +6,7 @@
 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)
diff --git a/legacy-test/Android.mk b/legacy-test/Android.mk
index 5e72a0d..0a814f3 100644
--- a/legacy-test/Android.mk
+++ b/legacy-test/Android.mk
@@ -18,7 +18,8 @@
 
 # Build the legacy-test library
 # =============================
-# This contains the junit.framework classes that were in Android API level 25.
+# This contains the junit.framework and android.test classes that were in
+# Android API level 25.
 include $(CLEAR_VARS)
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
@@ -28,6 +29,18 @@
 
 include $(BUILD_JAVA_LIBRARY)
 
+# Build the legacy-android-test library
+# =============================
+# This contains the android.test classes that were in Android API level 25.
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src/android)
+LOCAL_MODULE := legacy-android-test
+LOCAL_NO_STANDARD_LIBRARIES := true
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework junit
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
 ifeq ($(HOST_OS),linux)
 # Build the legacy-performance-test-hostdex library
 # =================================================
diff --git a/libs/androidfw/Android.bp b/libs/androidfw/Android.bp
index d501d25..fb89835 100644
--- a/libs/androidfw/Android.bp
+++ b/libs/androidfw/Android.bp
@@ -24,10 +24,14 @@
         "-Wunreachable-code",
     ],
     srcs: [
+        "ApkAssets.cpp",
         "Asset.cpp",
         "AssetDir.cpp",
         "AssetManager.cpp",
+        "AssetManager2.cpp",
         "AttributeResolution.cpp",
+        "ChunkIterator.cpp",
+        "LoadedArsc.cpp",
         "LocaleData.cpp",
         "misc.cpp",
         "ObbFile.cpp",
@@ -65,7 +69,16 @@
             shared: {
                 enabled: false,
             },
-            shared_libs: ["libz-host"],
+            static_libs: [
+                "libziparchive",
+                "libbase",
+                "liblog",
+                "libcutils",
+                "libutils",
+            ],
+            shared_libs: [
+                "libz-host",
+            ],
         },
         windows: {
             enabled: true,
diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp
new file mode 100644
index 0000000..55f4c3c
--- /dev/null
+++ b/libs/androidfw/ApkAssets.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_RESOURCES
+
+#include "androidfw/ApkAssets.h"
+
+#include "android-base/logging.h"
+#include "utils/Trace.h"
+#include "ziparchive/zip_archive.h"
+
+#include "androidfw/Asset.h"
+#include "androidfw/Util.h"
+
+namespace android {
+
+std::unique_ptr<ApkAssets> ApkAssets::Load(const std::string& path) {
+  ATRACE_NAME("ApkAssets::Load");
+  ::ZipArchiveHandle unmanaged_handle;
+  int32_t result = ::OpenArchive(path.c_str(), &unmanaged_handle);
+  if (result != 0) {
+    LOG(ERROR) << ::ErrorCodeString(result);
+    return {};
+  }
+
+  // Wrap the handle in a unique_ptr so it gets automatically closed.
+  std::unique_ptr<ApkAssets> loaded_apk(new ApkAssets());
+  loaded_apk->zip_handle_.reset(unmanaged_handle);
+
+  ::ZipString entry_name("resources.arsc");
+  ::ZipEntry entry;
+  result = ::FindEntry(loaded_apk->zip_handle_.get(), entry_name, &entry);
+  if (result != 0) {
+    LOG(ERROR) << ::ErrorCodeString(result);
+    return {};
+  }
+
+  if (entry.method == kCompressDeflated) {
+    LOG(WARNING) << "resources.arsc is compressed.";
+  }
+
+  loaded_apk->resources_asset_ =
+      loaded_apk->Open("resources.arsc", Asset::AccessMode::ACCESS_BUFFER);
+  if (loaded_apk->resources_asset_ == nullptr) {
+    return {};
+  }
+
+  loaded_apk->path_ = path;
+  loaded_apk->loaded_arsc_ =
+      LoadedArsc::Load(loaded_apk->resources_asset_->getBuffer(true /*wordAligned*/),
+                       loaded_apk->resources_asset_->getLength());
+  if (loaded_apk->loaded_arsc_ == nullptr) {
+    return {};
+  }
+  return loaded_apk;
+}
+
+std::unique_ptr<Asset> ApkAssets::Open(const std::string& path, Asset::AccessMode /*mode*/) const {
+  ATRACE_NAME("ApkAssets::Open");
+  CHECK(zip_handle_ != nullptr);
+
+  ::ZipString name(path.c_str());
+  ::ZipEntry entry;
+  int32_t result = ::FindEntry(zip_handle_.get(), name, &entry);
+  if (result != 0) {
+    LOG(ERROR) << "No entry '" << path << "' found in APK.";
+    return {};
+  }
+
+  if (entry.method == kCompressDeflated) {
+    auto compressed_asset = util::make_unique<_CompressedAsset>();
+    if (compressed_asset->openChunk(::GetFileDescriptor(zip_handle_.get()), entry.offset,
+                                    entry.method, entry.uncompressed_length,
+                                    entry.compressed_length) != NO_ERROR) {
+      LOG(ERROR) << "Failed to decompress '" << path << "'.";
+      return {};
+    }
+    return std::move(compressed_asset);
+  } else {
+    auto uncompressed_asset = util::make_unique<_FileAsset>();
+    if (uncompressed_asset->openChunk(path.c_str(), ::GetFileDescriptor(zip_handle_.get()),
+                                      entry.offset, entry.uncompressed_length) != NO_ERROR) {
+      LOG(ERROR) << "Failed to mmap '" << path << "'.";
+      return {};
+    }
+    return std::move(uncompressed_asset);
+  }
+  return {};
+}
+
+}  // namespace android
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
new file mode 100644
index 0000000..8d65925
--- /dev/null
+++ b/libs/androidfw/AssetManager2.cpp
@@ -0,0 +1,576 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_RESOURCES
+
+#include "androidfw/AssetManager2.h"
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "utils/ByteOrder.h"
+#include "utils/Trace.h"
+
+#ifdef _WIN32
+#ifdef ERROR
+#undef ERROR
+#endif
+#endif
+
+namespace android {
+
+AssetManager2::AssetManager2() { memset(&configuration_, 0, sizeof(configuration_)); }
+
+bool AssetManager2::SetApkAssets(const std::vector<const ApkAssets*>& apk_assets,
+                                 bool invalidate_caches) {
+  apk_assets_ = apk_assets;
+  if (invalidate_caches) {
+    InvalidateCaches(static_cast<uint32_t>(-1));
+  }
+  return true;
+}
+
+const std::vector<const ApkAssets*> AssetManager2::GetApkAssets() const { return apk_assets_; }
+
+const ResStringPool* AssetManager2::GetStringPoolForCookie(ApkAssetsCookie cookie) const {
+  if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
+    return nullptr;
+  }
+  return apk_assets_[cookie]->GetLoadedArsc()->GetStringPool();
+}
+
+void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
+  const int diff = configuration_.diff(configuration);
+  configuration_ = configuration;
+
+  if (diff) {
+    InvalidateCaches(static_cast<uint32_t>(diff));
+  }
+}
+
+const ResTable_config& AssetManager2::GetConfiguration() const { return configuration_; }
+
+std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, Asset::AccessMode mode) {
+  const std::string new_path = "assets/" + filename;
+  return OpenNonAsset(new_path, mode);
+}
+
+std::unique_ptr<Asset> AssetManager2::Open(const std::string& filename, ApkAssetsCookie cookie,
+                                           Asset::AccessMode mode) {
+  const std::string new_path = "assets/" + filename;
+  return OpenNonAsset(new_path, cookie, mode);
+}
+
+// Search in reverse because that's how we used to do it and we need to preserve behaviour.
+// This is unfortunate, because ClassLoaders delegate to the parent first, so the order
+// is inconsistent for split APKs.
+std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
+                                                   Asset::AccessMode mode,
+                                                   ApkAssetsCookie* out_cookie) {
+  ATRACE_CALL();
+  for (int32_t i = apk_assets_.size() - 1; i >= 0; i--) {
+    std::unique_ptr<Asset> asset = apk_assets_[i]->Open(filename, mode);
+    if (asset) {
+      if (out_cookie != nullptr) {
+        *out_cookie = i;
+      }
+      return asset;
+    }
+  }
+
+  if (out_cookie != nullptr) {
+    *out_cookie = kInvalidCookie;
+  }
+  return {};
+}
+
+std::unique_ptr<Asset> AssetManager2::OpenNonAsset(const std::string& filename,
+                                                   ApkAssetsCookie cookie, Asset::AccessMode mode) {
+  ATRACE_CALL();
+  if (cookie < 0 || static_cast<size_t>(cookie) >= apk_assets_.size()) {
+    return {};
+  }
+  return apk_assets_[cookie]->Open(filename, mode);
+}
+
+ApkAssetsCookie AssetManager2::FindEntry(uint32_t resid, uint16_t density_override,
+                                         bool stop_at_first_match, LoadedArsc::Entry* out_entry,
+                                         ResTable_config* out_selected_config,
+                                         uint32_t* out_flags) {
+  ATRACE_CALL();
+
+  // Might use this if density_override != 0.
+  ResTable_config density_override_config;
+
+  // Select our configuration or generate a density override configuration.
+  ResTable_config* desired_config = &configuration_;
+  if (density_override != 0 && density_override != configuration_.density) {
+    density_override_config = configuration_;
+    density_override_config.density = density_override;
+    desired_config = &density_override_config;
+  }
+
+  LoadedArsc::Entry best_entry;
+  ResTable_config best_config;
+  int32_t best_index = -1;
+  uint32_t cumulated_flags = 0;
+
+  const size_t apk_asset_count = apk_assets_.size();
+  for (size_t i = 0; i < apk_asset_count; i++) {
+    const LoadedArsc* loaded_arsc = apk_assets_[i]->GetLoadedArsc();
+
+    LoadedArsc::Entry current_entry;
+    ResTable_config current_config;
+    uint32_t flags = 0;
+    if (!loaded_arsc->FindEntry(resid, *desired_config, &current_entry, &current_config, &flags)) {
+      continue;
+    }
+
+    cumulated_flags |= flags;
+
+    if (best_index == -1 || current_config.isBetterThan(best_config, desired_config)) {
+      best_entry = current_entry;
+      best_config = current_config;
+      best_index = static_cast<int32_t>(i);
+      if (stop_at_first_match) {
+        break;
+      }
+    }
+  }
+
+  if (best_index == -1) {
+    return kInvalidCookie;
+  }
+
+  *out_entry = best_entry;
+  *out_selected_config = best_config;
+  *out_flags = cumulated_flags;
+  return best_index;
+}
+
+bool AssetManager2::GetResourceName(uint32_t resid, ResourceName* out_name) {
+  ATRACE_CALL();
+
+  LoadedArsc::Entry entry;
+  ResTable_config config;
+  uint32_t flags = 0u;
+  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+                                     true /* stop_at_first_match */, &entry, &config, &flags);
+  if (cookie == kInvalidCookie) {
+    return false;
+  }
+
+  const std::string* package_name =
+      apk_assets_[cookie]->GetLoadedArsc()->GetPackageNameForId(resid);
+  if (package_name == nullptr) {
+    return false;
+  }
+
+  out_name->package = package_name->data();
+  out_name->package_len = package_name->size();
+
+  out_name->type = entry.type_string_ref.string8(&out_name->type_len);
+  out_name->type16 = nullptr;
+  if (out_name->type == nullptr) {
+    out_name->type16 = entry.type_string_ref.string16(&out_name->type_len);
+    if (out_name->type16 == nullptr) {
+      return false;
+    }
+  }
+
+  out_name->entry = entry.entry_string_ref.string8(&out_name->entry_len);
+  out_name->entry16 = nullptr;
+  if (out_name->entry == nullptr) {
+    out_name->entry16 = entry.entry_string_ref.string16(&out_name->entry_len);
+    if (out_name->entry16 == nullptr) {
+      return false;
+    }
+  }
+  return true;
+}
+
+bool AssetManager2::GetResourceFlags(uint32_t resid, uint32_t* out_flags) {
+  LoadedArsc::Entry entry;
+  ResTable_config config;
+  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+                                     false /* stop_at_first_match */, &entry, &config, out_flags);
+  return cookie != kInvalidCookie;
+}
+
+ApkAssetsCookie AssetManager2::GetResource(uint32_t resid, bool may_be_bag,
+                                           uint16_t density_override, Res_value* out_value,
+                                           ResTable_config* out_selected_config,
+                                           uint32_t* out_flags) {
+  ATRACE_CALL();
+
+  LoadedArsc::Entry entry;
+  ResTable_config config;
+  uint32_t flags = 0u;
+  ApkAssetsCookie cookie =
+      FindEntry(resid, density_override, false /* stop_at_first_match */, &entry, &config, &flags);
+  if (cookie == kInvalidCookie) {
+    return kInvalidCookie;
+  }
+
+  if (dtohl(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) {
+    if (!may_be_bag) {
+      LOG(ERROR) << base::StringPrintf("Resource %08x is a complex map type.", resid);
+    }
+    return kInvalidCookie;
+  }
+
+  const Res_value* device_value = reinterpret_cast<const Res_value*>(
+      reinterpret_cast<const uint8_t*>(entry.entry) + dtohs(entry.entry->size));
+  out_value->copyFrom_dtoh(*device_value);
+  *out_selected_config = config;
+  *out_flags = flags;
+  return cookie;
+}
+
+const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
+  ATRACE_CALL();
+
+  auto cached_iter = cached_bags_.find(resid);
+  if (cached_iter != cached_bags_.end()) {
+    return cached_iter->second.get();
+  }
+
+  LoadedArsc::Entry entry;
+  ResTable_config config;
+  uint32_t flags = 0u;
+  ApkAssetsCookie cookie = FindEntry(resid, 0u /* density_override */,
+                                     false /* stop_at_first_match */, &entry, &config, &flags);
+  if (cookie == kInvalidCookie) {
+    return nullptr;
+  }
+
+  // Check that the size of the entry header is at least as big as
+  // the desired ResTable_map_entry. Also verify that the entry
+  // was intended to be a map.
+  if (dtohs(entry.entry->size) < sizeof(ResTable_map_entry) ||
+      (dtohs(entry.entry->flags) & ResTable_entry::FLAG_COMPLEX) == 0) {
+    // Not a bag, nothing to do.
+    return nullptr;
+  }
+
+  const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry.entry);
+  const ResTable_map* map_entry =
+      reinterpret_cast<const ResTable_map*>(reinterpret_cast<const uint8_t*>(map) + map->size);
+  const ResTable_map* const map_entry_end = map_entry + dtohl(map->count);
+
+  const uint32_t parent = dtohl(map->parent.ident);
+  if (parent == 0) {
+    // There is no parent, meaning there is nothing to inherit and we can do a simple
+    // copy of the entries in the map.
+    const size_t entry_count = map_entry_end - map_entry;
+    util::unique_cptr<ResolvedBag> new_bag{reinterpret_cast<ResolvedBag*>(
+        malloc(sizeof(ResolvedBag) + (entry_count * sizeof(ResolvedBag::Entry))))};
+    ResolvedBag::Entry* new_entry = new_bag->entries;
+    for (; map_entry != map_entry_end; ++map_entry) {
+      new_entry->cookie = cookie;
+      new_entry->value.copyFrom_dtoh(map_entry->value);
+      new_entry->key = dtohl(map_entry->name.ident);
+      new_entry->key_pool = nullptr;
+      new_entry->type_pool = nullptr;
+      ++new_entry;
+    }
+    new_bag->type_spec_flags = flags;
+    new_bag->entry_count = static_cast<uint32_t>(entry_count);
+    ResolvedBag* result = new_bag.get();
+    cached_bags_[resid] = std::move(new_bag);
+    return result;
+  }
+
+  // Get the parent and do a merge of the keys.
+  const ResolvedBag* parent_bag = GetBag(parent);
+  if (parent_bag == nullptr) {
+    // Failed to get the parent that should exist.
+    return nullptr;
+  }
+
+  // Combine flags from the parent and our own bag.
+  flags |= parent_bag->type_spec_flags;
+
+  // Create the max possible entries we can make. Once we construct the bag,
+  // we will realloc to fit to size.
+  const size_t max_count = parent_bag->entry_count + dtohl(map->count);
+  ResolvedBag* new_bag = reinterpret_cast<ResolvedBag*>(
+      malloc(sizeof(ResolvedBag) + (max_count * sizeof(ResolvedBag::Entry))));
+  ResolvedBag::Entry* new_entry = new_bag->entries;
+
+  const ResolvedBag::Entry* parent_entry = parent_bag->entries;
+  const ResolvedBag::Entry* const parent_entry_end = parent_entry + parent_bag->entry_count;
+
+  // The keys are expected to be in sorted order. Merge the two bags.
+  while (map_entry != map_entry_end && parent_entry != parent_entry_end) {
+    const uint32_t child_key = dtohl(map_entry->name.ident);
+    if (child_key <= parent_entry->key) {
+      // Use the child key if it comes before the parent
+      // or is equal to the parent (overrides).
+      new_entry->cookie = cookie;
+      new_entry->value.copyFrom_dtoh(map_entry->value);
+      new_entry->key = child_key;
+      new_entry->key_pool = nullptr;
+      new_entry->type_pool = nullptr;
+      ++map_entry;
+    } else {
+      // Take the parent entry as-is.
+      memcpy(new_entry, parent_entry, sizeof(*new_entry));
+    }
+
+    if (child_key >= parent_entry->key) {
+      // Move to the next parent entry if we used it or it was overridden.
+      ++parent_entry;
+    }
+    // Increment to the next entry to fill.
+    ++new_entry;
+  }
+
+  // Finish the child entries if they exist.
+  while (map_entry != map_entry_end) {
+    new_entry->cookie = cookie;
+    new_entry->value.copyFrom_dtoh(map_entry->value);
+    new_entry->key = dtohl(map_entry->name.ident);
+    new_entry->key_pool = nullptr;
+    new_entry->type_pool = nullptr;
+    ++map_entry;
+    ++new_entry;
+  }
+
+  // Finish the parent entries if they exist.
+  if (parent_entry != parent_entry_end) {
+    // Take the rest of the parent entries as-is.
+    const size_t num_entries_to_copy = parent_entry_end - parent_entry;
+    memcpy(new_entry, parent_entry, num_entries_to_copy * sizeof(*new_entry));
+    new_entry += num_entries_to_copy;
+  }
+
+  // Resize the resulting array to fit.
+  const size_t actual_count = new_entry - new_bag->entries;
+  if (actual_count != max_count) {
+    new_bag = reinterpret_cast<ResolvedBag*>(
+        realloc(new_bag, sizeof(ResolvedBag) + (actual_count * sizeof(ResolvedBag::Entry))));
+  }
+
+  util::unique_cptr<ResolvedBag> final_bag{new_bag};
+  final_bag->type_spec_flags = flags;
+  final_bag->entry_count = static_cast<uint32_t>(actual_count);
+  ResolvedBag* result = final_bag.get();
+  cached_bags_[resid] = std::move(final_bag);
+  return result;
+}
+
+void AssetManager2::InvalidateCaches(uint32_t diff) {
+  if (diff == 0xffffffffu) {
+    // Everything must go.
+    cached_bags_.clear();
+    return;
+  }
+
+  // Be more conservative with what gets purged. Only if the bag has other possible
+  // variations with respect to what changed (diff) should we remove it.
+  for (auto iter = cached_bags_.cbegin(); iter != cached_bags_.cend();) {
+    if (diff & iter->second->type_spec_flags) {
+      iter = cached_bags_.erase(iter);
+    } else {
+      ++iter;
+    }
+  }
+}
+
+std::unique_ptr<Theme> AssetManager2::NewTheme() { return std::unique_ptr<Theme>(new Theme(this)); }
+
+bool Theme::ApplyStyle(uint32_t resid, bool force) {
+  ATRACE_CALL();
+
+  const ResolvedBag* bag = asset_manager_->GetBag(resid);
+  if (bag == nullptr) {
+    return false;
+  }
+
+  // Merge the flags from this style.
+  type_spec_flags_ |= bag->type_spec_flags;
+
+  // On the first iteration, verify the attribute IDs and
+  // update the entry count in each type.
+  const auto bag_iter_end = end(bag);
+  for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) {
+    const uint32_t attr_resid = bag_iter->key;
+
+    // If the resource ID passed in is not a style, the key can be
+    // some other identifier that is not a resource ID.
+    if (!util::is_valid_resid(attr_resid)) {
+      return false;
+    }
+
+    const uint32_t package_idx = util::get_package_id(attr_resid);
+
+    // The type ID is 1-based, so subtract 1 to get an index.
+    const uint32_t type_idx = util::get_type_id(attr_resid) - 1;
+    const uint32_t entry_idx = util::get_entry_id(attr_resid);
+
+    std::unique_ptr<Package>& package = packages_[package_idx];
+    if (package == nullptr) {
+      package.reset(new Package());
+    }
+
+    util::unique_cptr<Type>& type = package->types[type_idx];
+    if (type == nullptr) {
+      // Set the initial capacity to take up a total amount of 1024 bytes.
+      constexpr uint32_t kInitialCapacity = (1024u - sizeof(Type)) / sizeof(Entry);
+      const uint32_t initial_capacity = std::max(entry_idx, kInitialCapacity);
+      type.reset(
+          reinterpret_cast<Type*>(calloc(sizeof(Type) + (initial_capacity * sizeof(Entry)), 1)));
+      type->entry_capacity = initial_capacity;
+    }
+
+    // Set the entry_count to include this entry. We will populate
+    // and resize the array as necessary in the next pass.
+    if (entry_idx + 1 > type->entry_count) {
+      // Increase the entry count to include this.
+      type->entry_count = entry_idx + 1;
+    }
+  }
+
+  // On the second pass, we will realloc to fit the entry counts
+  // and populate the structures.
+  for (auto bag_iter = begin(bag); bag_iter != bag_iter_end; ++bag_iter) {
+    const uint32_t attr_resid = bag_iter->key;
+    const uint32_t package_idx = util::get_package_id(attr_resid);
+    const uint32_t type_idx = util::get_type_id(attr_resid) - 1;
+    const uint32_t entry_idx = util::get_entry_id(attr_resid);
+    Package* package = packages_[package_idx].get();
+    util::unique_cptr<Type>& type = package->types[type_idx];
+    if (type->entry_count != type->entry_capacity) {
+      // Resize to fit the actual entries that will be included.
+      Type* type_ptr = type.release();
+      type.reset(reinterpret_cast<Type*>(
+          realloc(type_ptr, sizeof(Type) + (type_ptr->entry_count * sizeof(Entry)))));
+      if (type->entry_capacity < type->entry_count) {
+        // Clear the newly allocated memory (which does not get zero initialized).
+        // We need to do this because we |= type_spec_flags.
+        memset(type->entries + type->entry_capacity, 0,
+               sizeof(Entry) * (type->entry_count - type->entry_capacity));
+      }
+      type->entry_capacity = type->entry_count;
+    }
+    Entry& entry = type->entries[entry_idx];
+    if (force || entry.value.dataType == Res_value::TYPE_NULL) {
+      entry.cookie = bag_iter->cookie;
+      entry.type_spec_flags |= bag->type_spec_flags;
+      entry.value = bag_iter->value;
+    }
+  }
+  return true;
+}
+
+ApkAssetsCookie Theme::GetAttribute(uint32_t resid, Res_value* out_value,
+                                    uint32_t* out_flags) const {
+  constexpr const int kMaxIterations = 20;
+
+  uint32_t type_spec_flags = 0u;
+
+  for (int iterations_left = kMaxIterations; iterations_left > 0; iterations_left--) {
+    if (!util::is_valid_resid(resid)) {
+      return kInvalidCookie;
+    }
+
+    const uint32_t package_idx = util::get_package_id(resid);
+
+    // Type ID is 1-based, subtract 1 to get the index.
+    const uint32_t type_idx = util::get_type_id(resid) - 1;
+    const uint32_t entry_idx = util::get_entry_id(resid);
+
+    const Package* package = packages_[package_idx].get();
+    if (package == nullptr) {
+      return kInvalidCookie;
+    }
+
+    const Type* type = package->types[type_idx].get();
+    if (type == nullptr) {
+      return kInvalidCookie;
+    }
+
+    if (entry_idx >= type->entry_count) {
+      return kInvalidCookie;
+    }
+
+    const Entry& entry = type->entries[entry_idx];
+    type_spec_flags |= entry.type_spec_flags;
+
+    switch (entry.value.dataType) {
+      case Res_value::TYPE_ATTRIBUTE:
+        resid = entry.value.data;
+        break;
+
+      case Res_value::TYPE_NULL:
+        return kInvalidCookie;
+
+      default:
+        *out_value = entry.value;
+        if (out_flags != nullptr) {
+          *out_flags = type_spec_flags;
+        }
+        return entry.cookie;
+    }
+  }
+
+  LOG(WARNING) << base::StringPrintf("Too many (%d) attribute references, stopped at: 0x%08x",
+                                     kMaxIterations, resid);
+  return kInvalidCookie;
+}
+
+void Theme::Clear() {
+  type_spec_flags_ = 0u;
+  for (std::unique_ptr<Package>& package : packages_) {
+    package.reset();
+  }
+}
+
+bool Theme::SetTo(const Theme& o) {
+  if (this == &o) {
+    return true;
+  }
+
+  if (asset_manager_ != o.asset_manager_) {
+    return false;
+  }
+
+  type_spec_flags_ = o.type_spec_flags_;
+
+  for (size_t p = 0; p < arraysize(packages_); p++) {
+    const Package* package = o.packages_[p].get();
+    if (package == nullptr) {
+      packages_[p].reset();
+      continue;
+    }
+
+    for (size_t t = 0; t < arraysize(package->types); t++) {
+      const Type* type = package->types[t].get();
+      if (type == nullptr) {
+        packages_[p]->types[t].reset();
+        continue;
+      }
+
+      const size_t type_alloc_size = sizeof(Type) + (type->entry_capacity * sizeof(Entry));
+      void* copied_data = malloc(type_alloc_size);
+      memcpy(copied_data, type, type_alloc_size);
+      packages_[p]->types[t].reset(reinterpret_cast<Type*>(copied_data));
+    }
+  }
+  return true;
+}
+
+}  // namespace android
diff --git a/libs/androidfw/Chunk.h b/libs/androidfw/Chunk.h
new file mode 100644
index 0000000..e87b940
--- /dev/null
+++ b/libs/androidfw/Chunk.h
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+#ifndef CHUNK_H_
+#define CHUNK_H_
+
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "utils/ByteOrder.h"
+
+#ifdef _WIN32
+#ifdef ERROR
+#undef ERROR
+#endif
+#endif
+
+#include "androidfw/ResourceTypes.h"
+
+namespace android {
+
+// Helpful wrapper around a ResChunk_header that provides getter methods
+// that handle endianness conversions and provide access to the data portion
+// of the chunk.
+class Chunk {
+ public:
+  explicit Chunk(const ResChunk_header* chunk) : device_chunk_(chunk) {}
+
+  // Returns the type of the chunk. Caller need not worry about endianness.
+  inline int type() const { return dtohs(device_chunk_->type); }
+
+  // Returns the size of the entire chunk. This can be useful for skipping
+  // over the entire chunk. Caller need not worry about endianness.
+  inline size_t size() const { return dtohl(device_chunk_->size); }
+
+  // Returns the size of the header. Caller need not worry about endianness.
+  inline size_t header_size() const { return dtohs(device_chunk_->headerSize); }
+
+  template <typename T>
+  inline const T* header() const {
+    if (header_size() >= sizeof(T)) {
+      return reinterpret_cast<const T*>(device_chunk_);
+    }
+    return nullptr;
+  }
+
+  inline const void* data_ptr() const {
+    return reinterpret_cast<const uint8_t*>(device_chunk_) + header_size();
+  }
+
+  inline size_t data_size() const { return size() - header_size(); }
+
+ private:
+  const ResChunk_header* device_chunk_;
+};
+
+// Provides a Java style iterator over an array of ResChunk_header's.
+// Validation is performed while iterating.
+// The caller should check if there was an error during chunk validation
+// by calling HadError() and GetLastError() to get the reason for failure.
+// Example:
+//
+//   ChunkIterator iter(data_ptr, data_len);
+//   while (iter.HasNext()) {
+//     const Chunk chunk = iter.Next();
+//     ...
+//   }
+//
+//   if (iter.HadError()) {
+//     LOG(ERROR) << iter.GetLastError();
+//   }
+//
+class ChunkIterator {
+ public:
+  ChunkIterator(const void* data, size_t len)
+      : next_chunk_(reinterpret_cast<const ResChunk_header*>(data)),
+        len_(len),
+        last_error_(nullptr) {
+    CHECK(next_chunk_ != nullptr) << "data can't be nullptr";
+    VerifyNextChunk();
+  }
+
+  Chunk Next();
+  inline bool HasNext() const { return !HadError() && len_ != 0; };
+  inline bool HadError() const { return last_error_ != nullptr; }
+  inline std::string GetLastError() const { return last_error_; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ChunkIterator);
+
+  // Returns false if there was an error.
+  bool VerifyNextChunk();
+
+  const ResChunk_header* next_chunk_;
+  size_t len_;
+  const char* last_error_;
+};
+
+}  // namespace android
+
+#endif /* CHUNK_H_ */
diff --git a/libs/androidfw/ChunkIterator.cpp b/libs/androidfw/ChunkIterator.cpp
new file mode 100644
index 0000000..747aa4a
--- /dev/null
+++ b/libs/androidfw/ChunkIterator.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+#include "Chunk.h"
+
+#include "android-base/logging.h"
+
+namespace android {
+
+Chunk ChunkIterator::Next() {
+  CHECK(len_ != 0) << "called Next() after last chunk";
+
+  const ResChunk_header* this_chunk = next_chunk_;
+
+  // We've already checked the values of this_chunk, so safely increment.
+  next_chunk_ = reinterpret_cast<const ResChunk_header*>(
+      reinterpret_cast<const uint8_t*>(this_chunk) + dtohl(this_chunk->size));
+  len_ -= dtohl(this_chunk->size);
+
+  if (len_ != 0) {
+    // Prepare the next chunk.
+    VerifyNextChunk();
+  }
+  return Chunk(this_chunk);
+}
+
+// Returns false if there was an error.
+bool ChunkIterator::VerifyNextChunk() {
+  const uintptr_t header_start = reinterpret_cast<uintptr_t>(next_chunk_);
+
+  // This data must be 4-byte aligned, since we directly
+  // access 32-bit words, which must be aligned on
+  // certain architectures.
+  if (header_start & 0x03) {
+    last_error_ = "header not aligned on 4-byte boundary";
+    return false;
+  }
+
+  if (len_ < sizeof(ResChunk_header)) {
+    last_error_ = "not enough space for header";
+    return false;
+  }
+
+  const size_t header_size = dtohs(next_chunk_->headerSize);
+  const size_t size = dtohl(next_chunk_->size);
+  if (header_size < sizeof(ResChunk_header)) {
+    last_error_ = "header size too small";
+    return false;
+  }
+
+  if (header_size > size) {
+    last_error_ = "header size is larger than entire chunk";
+    return false;
+  }
+
+  if (size > len_) {
+    last_error_ = "chunk size is bigger than given data";
+    return false;
+  }
+
+  if ((size | header_size) & 0x03) {
+    last_error_ = "header sizes are not aligned on 4-byte boundary";
+    return false;
+  }
+  return true;
+}
+
+}  // namespace android
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
new file mode 100644
index 0000000..94d0d46
--- /dev/null
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -0,0 +1,572 @@
+/*
+ * 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.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_RESOURCES
+
+#include "androidfw/LoadedArsc.h"
+
+#include <cstddef>
+#include <limits>
+
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+#include "utils/ByteOrder.h"
+#include "utils/Trace.h"
+
+#ifdef _WIN32
+#ifdef ERROR
+#undef ERROR
+#endif
+#endif
+
+#include "Chunk.h"
+#include "androidfw/ByteBucketArray.h"
+#include "androidfw/Util.h"
+
+using android::base::StringPrintf;
+
+namespace android {
+
+namespace {
+
+// Element of a TypeSpec array. See TypeSpec.
+struct Type {
+  // The configuration for which this type defines entries.
+  // This is already converted to host endianness.
+  ResTable_config configuration;
+
+  // Pointer to the mmapped data where entry definitions are kept.
+  const ResTable_type* type;
+};
+
+// TypeSpec is going to be immediately proceeded by
+// an array of Type structs, all in the same block of memory.
+struct TypeSpec {
+  // Pointer to the mmapped data where flags are kept.
+  // Flags denote whether the resource entry is public
+  // and under which configurations it varies.
+  const ResTable_typeSpec* type_spec;
+
+  // The number of types that follow this struct.
+  // There is a type for each configuration
+  // that entries are defined for.
+  size_t type_count;
+
+  // Trick to easily access a variable number of Type structs
+  // proceeding this struct, and to ensure their alignment.
+  const Type types[0];
+};
+
+// TypeSpecPtr points to the block of memory that holds
+// a TypeSpec struct, followed by an array of Type structs.
+// TypeSpecPtr is a managed pointer that knows how to delete
+// itself.
+using TypeSpecPtr = util::unique_cptr<TypeSpec>;
+
+// Builder that helps accumulate Type structs and then create a single
+// contiguous block of memory to store both the TypeSpec struct and
+// the Type structs.
+class TypeSpecPtrBuilder {
+ public:
+  TypeSpecPtrBuilder(const ResTable_typeSpec* header) : header_(header) {}
+
+  void AddType(const ResTable_type* type) {
+    ResTable_config config;
+    config.copyFromDtoH(type->config);
+    types_.push_back(Type{config, type});
+  }
+
+  TypeSpecPtr Build() {
+    // Check for overflow.
+    if ((std::numeric_limits<size_t>::max() - sizeof(TypeSpec)) / sizeof(Type) < types_.size()) {
+      return {};
+    }
+    TypeSpec* type_spec = (TypeSpec*)::malloc(sizeof(TypeSpec) + (types_.size() * sizeof(Type)));
+    type_spec->type_spec = header_;
+    type_spec->type_count = types_.size();
+    memcpy(type_spec + 1, types_.data(), types_.size() * sizeof(Type));
+    return TypeSpecPtr(type_spec);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(TypeSpecPtrBuilder);
+
+  const ResTable_typeSpec* header_;
+  std::vector<Type> types_;
+};
+
+}  // namespace
+
+class LoadedPackage {
+ public:
+  LoadedPackage() = default;
+
+  bool FindEntry(uint8_t type_id, uint16_t entry_id, const ResTable_config& config,
+                 LoadedArsc::Entry* out_entry, ResTable_config* out_selected_config,
+                 uint32_t* out_flags) const;
+
+  ResStringPool type_string_pool_;
+  ResStringPool key_string_pool_;
+  std::string package_name_;
+  int package_id_ = -1;
+
+  ByteBucketArray<TypeSpecPtr> type_specs_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
+};
+
+bool LoadedPackage::FindEntry(uint8_t type_id, uint16_t entry_id, const ResTable_config& config,
+                              LoadedArsc::Entry* out_entry, ResTable_config* out_selected_config,
+                              uint32_t* out_flags) const {
+  ATRACE_NAME("LoadedPackage::FindEntry");
+  const TypeSpecPtr& ptr = type_specs_[type_id];
+  if (ptr == nullptr) {
+    return false;
+  }
+
+  // Don't bother checking if the entry ID is larger than
+  // the number of entries.
+  if (entry_id >= dtohl(ptr->type_spec->entryCount)) {
+    return false;
+  }
+
+  const ResTable_config* best_config = nullptr;
+  const ResTable_type* best_type = nullptr;
+  uint32_t best_offset = 0;
+
+  for (uint32_t i = 0; i < ptr->type_count; i++) {
+    const Type* type = &ptr->types[i];
+
+    if (type->configuration.match(config) &&
+        (best_config == nullptr || type->configuration.isBetterThan(*best_config, &config))) {
+      // The configuration matches and is better than the previous selection.
+      // Find the entry value if it exists for this configuration.
+      size_t entry_count = dtohl(type->type->entryCount);
+      if (entry_id < entry_count) {
+        const uint32_t* entry_offsets = reinterpret_cast<const uint32_t*>(
+            reinterpret_cast<const uint8_t*>(type->type) + dtohs(type->type->header.headerSize));
+        const uint32_t offset = dtohl(entry_offsets[entry_id]);
+        if (offset != ResTable_type::NO_ENTRY) {
+          // There is an entry for this resource, record it.
+          best_config = &type->configuration;
+          best_type = type->type;
+          best_offset = offset + dtohl(type->type->entriesStart);
+        }
+      }
+    }
+  }
+
+  if (best_type == nullptr) {
+    return false;
+  }
+
+  const uint32_t* flags = reinterpret_cast<const uint32_t*>(ptr->type_spec + 1);
+  *out_flags = dtohl(flags[entry_id]);
+  *out_selected_config = *best_config;
+
+  const ResTable_entry* best_entry = reinterpret_cast<const ResTable_entry*>(
+      reinterpret_cast<const uint8_t*>(best_type) + best_offset);
+  out_entry->entry = best_entry;
+  out_entry->type_string_ref = StringPoolRef(&type_string_pool_, best_type->id - 1);
+  out_entry->entry_string_ref = StringPoolRef(&key_string_pool_, dtohl(best_entry->key.index));
+  return true;
+}
+
+// The destructor gets generated into arbitrary translation units
+// if left implicit, which causes the compiler to complain about
+// forward declarations and incomplete types.
+LoadedArsc::~LoadedArsc() {}
+
+bool LoadedArsc::FindEntry(uint32_t resid, const ResTable_config& config, Entry* out_entry,
+                           ResTable_config* out_selected_config, uint32_t* out_flags) const {
+  ATRACE_NAME("LoadedArsc::FindEntry");
+  const uint8_t package_id = util::get_package_id(resid);
+  const uint8_t type_id = util::get_type_id(resid);
+  const uint16_t entry_id = util::get_entry_id(resid);
+
+  if (type_id == 0) {
+    LOG(ERROR) << "Invalid ID 0x" << std::hex << resid << std::dec << ".";
+    return false;
+  }
+
+  for (const auto& loaded_package : packages_) {
+    if (loaded_package->package_id_ == package_id) {
+      return loaded_package->FindEntry(type_id - 1, entry_id, config, out_entry,
+                                       out_selected_config, out_flags);
+    }
+  }
+  return false;
+}
+
+const std::string* LoadedArsc::GetPackageNameForId(uint32_t resid) const {
+  const uint8_t package_id = util::get_package_id(resid);
+  for (const auto& loaded_package : packages_) {
+    if (loaded_package->package_id_ == package_id) {
+      return &loaded_package->package_name_;
+    }
+  }
+  return nullptr;
+}
+
+static bool VerifyType(const Chunk& chunk) {
+  ATRACE_CALL();
+  const ResTable_type* header = chunk.header<ResTable_type>();
+
+  const size_t entry_count = dtohl(header->entryCount);
+  if (entry_count > std::numeric_limits<uint16_t>::max()) {
+    LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_TYPE.";
+    return false;
+  }
+
+  // Make sure that there is enough room for the entry offsets.
+  const size_t offsets_offset = chunk.header_size();
+  const size_t entries_offset = dtohl(header->entriesStart);
+  const size_t offsets_length = sizeof(uint32_t) * entry_count;
+
+  if (offsets_offset + offsets_length > entries_offset) {
+    LOG(ERROR) << "Entry offsets overlap actual entry data.";
+    return false;
+  }
+
+  if (entries_offset > chunk.size()) {
+    LOG(ERROR) << "Entry offsets extend beyond chunk.";
+    return false;
+  }
+
+  if (entries_offset & 0x03) {
+    LOG(ERROR) << "Entries start at unaligned address.";
+    return false;
+  }
+
+  // Check each entry offset.
+  const uint32_t* offsets =
+      reinterpret_cast<const uint32_t*>(reinterpret_cast<const uint8_t*>(header) + offsets_offset);
+  for (size_t i = 0; i < entry_count; i++) {
+    uint32_t offset = dtohl(offsets[i]);
+    if (offset != ResTable_type::NO_ENTRY) {
+      // Check that the offset is aligned.
+      if (offset & 0x03) {
+        LOG(ERROR) << "Entry offset at index " << i << " is not 4-byte aligned.";
+        return false;
+      }
+
+      // Check that the offset doesn't overflow.
+      if (offset > std::numeric_limits<uint32_t>::max() - entries_offset) {
+        // Overflow in offset.
+        LOG(ERROR) << "Entry offset at index " << i << " is too large.";
+        return false;
+      }
+
+      offset += entries_offset;
+      if (offset > chunk.size() - sizeof(ResTable_entry)) {
+        LOG(ERROR) << "Entry offset at index " << i << " is too large. No room for ResTable_entry.";
+        return false;
+      }
+
+      const ResTable_entry* entry = reinterpret_cast<const ResTable_entry*>(
+          reinterpret_cast<const uint8_t*>(header) + offset);
+      const size_t entry_size = dtohs(entry->size);
+      if (entry_size < sizeof(*entry)) {
+        LOG(ERROR) << "ResTable_entry size " << entry_size << " is too small.";
+        return false;
+      }
+
+      // Check the declared entrySize.
+      if (entry_size > chunk.size() || offset > chunk.size() - entry_size) {
+        LOG(ERROR) << "ResTable_entry size " << entry_size << " is too large.";
+        return false;
+      }
+
+      // If this is a map entry, then keep validating.
+      if (entry_size >= sizeof(ResTable_map_entry)) {
+        const ResTable_map_entry* map = reinterpret_cast<const ResTable_map_entry*>(entry);
+        const size_t map_entry_count = dtohl(map->count);
+
+        size_t map_entries_start = offset + entry_size;
+        if (map_entries_start & 0x03) {
+          LOG(ERROR) << "Map entries start at unaligned offset.";
+          return false;
+        }
+
+        // Each entry is sizeof(ResTable_map) big.
+        if (map_entry_count > ((chunk.size() - map_entries_start) / sizeof(ResTable_map))) {
+          LOG(ERROR) << "Too many map entries in ResTable_map_entry.";
+          return false;
+        }
+
+        // Great, all the map entries fit!.
+      } else {
+        // There needs to be room for one Res_value struct.
+        if (offset + entry_size > chunk.size() - sizeof(Res_value)) {
+          LOG(ERROR) << "No room for Res_value after ResTable_entry.";
+          return false;
+        }
+
+        const Res_value* value = reinterpret_cast<const Res_value*>(
+            reinterpret_cast<const uint8_t*>(entry) + entry_size);
+        const size_t value_size = dtohs(value->size);
+        if (value_size < sizeof(Res_value)) {
+          LOG(ERROR) << "Res_value is too small.";
+          return false;
+        }
+
+        if (value_size > chunk.size() || offset + entry_size > chunk.size() - value_size) {
+          LOG(ERROR) << "Res_value size is too large.";
+          return false;
+        }
+      }
+    }
+  }
+  return true;
+}
+
+static bool LoadPackage(const Chunk& chunk, LoadedPackage* loaded_package) {
+  ATRACE_CALL();
+  const ResTable_package* header = chunk.header<ResTable_package>();
+  if (header == nullptr) {
+    LOG(ERROR) << "Chunk RES_TABLE_PACKAGE_TYPE is too small.";
+    return false;
+  }
+
+  loaded_package->package_id_ = dtohl(header->id);
+
+  // A TypeSpec builder. We use this to accumulate the set of Types
+  // available for a TypeSpec, and later build a single, contiguous block
+  // of memory that holds all the Types together with the TypeSpec.
+  std::unique_ptr<TypeSpecPtrBuilder> types_builder;
+
+  // Keep track of the last seen type index. Since type IDs are 1-based,
+  // this records their index, which is 0-based (type ID - 1).
+  uint8_t last_type_idx = 0;
+
+  ChunkIterator iter(chunk.data_ptr(), chunk.data_size());
+  while (iter.HasNext()) {
+    const Chunk child_chunk = iter.Next();
+    switch (child_chunk.type()) {
+      case RES_STRING_POOL_TYPE: {
+        const uintptr_t pool_address =
+            reinterpret_cast<uintptr_t>(child_chunk.header<ResChunk_header>());
+        const uintptr_t header_address = reinterpret_cast<uintptr_t>(header);
+        if (pool_address == header_address + dtohl(header->typeStrings)) {
+          // This string pool is the type string pool.
+          status_t err = loaded_package->type_string_pool_.setTo(
+              child_chunk.header<ResStringPool_header>(), child_chunk.size());
+          if (err != NO_ERROR) {
+            LOG(ERROR) << "Corrupt package type string pool.";
+            return false;
+          }
+        } else if (pool_address == header_address + dtohl(header->keyStrings)) {
+          // This string pool is the key string pool.
+          status_t err = loaded_package->key_string_pool_.setTo(
+              child_chunk.header<ResStringPool_header>(), child_chunk.size());
+          if (err != NO_ERROR) {
+            LOG(ERROR) << "Corrupt package key string pool.";
+            return false;
+          }
+        } else {
+          LOG(WARNING) << "Too many string pool chunks found in package.";
+        }
+      } break;
+
+      case RES_TABLE_TYPE_SPEC_TYPE: {
+        ATRACE_NAME("LoadTableTypeSpec");
+
+        // Starting a new TypeSpec, so finish the old one if there was one.
+        if (types_builder) {
+          TypeSpecPtr type_spec_ptr = types_builder->Build();
+          if (type_spec_ptr == nullptr) {
+            LOG(ERROR) << "Too many type configurations, overflow detected.";
+            return false;
+          }
+
+          loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+
+          types_builder = {};
+          last_type_idx = 0;
+        }
+
+        const ResTable_typeSpec* type_spec = child_chunk.header<ResTable_typeSpec>();
+        if (type_spec == nullptr) {
+          LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE is too small.";
+          return false;
+        }
+
+        if (type_spec->id == 0) {
+          LOG(ERROR) << "Chunk RES_TABLE_TYPE_SPEC_TYPE has invalid ID 0.";
+          return false;
+        }
+
+        // The data portion of this chunk contains entry_count 32bit entries,
+        // each one representing a set of flags.
+        // Here we only validate that the chunk is well formed.
+        const size_t entry_count = dtohl(type_spec->entryCount);
+
+        // There can only be 2^16 entries in a type, because that is the ID
+        // space for entries (EEEE) in the resource ID 0xPPTTEEEE.
+        if (entry_count > std::numeric_limits<uint16_t>::max()) {
+          LOG(ERROR) << "Too many entries in RES_TABLE_TYPE_SPEC_TYPE: " << entry_count << ".";
+          return false;
+        }
+
+        if (entry_count * sizeof(uint32_t) > chunk.data_size()) {
+          LOG(ERROR) << "Chunk too small to hold entries in RES_TABLE_TYPE_SPEC_TYPE.";
+          return false;
+        }
+
+        last_type_idx = type_spec->id - 1;
+        types_builder = util::make_unique<TypeSpecPtrBuilder>(type_spec);
+      } break;
+
+      case RES_TABLE_TYPE_TYPE: {
+        const ResTable_type* type = child_chunk.header<ResTable_type>();
+        if (type == nullptr) {
+          LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE is too small.";
+          return false;
+        }
+
+        if (type->id == 0) {
+          LOG(ERROR) << "Chunk RES_TABLE_TYPE_TYPE has invalid ID 0.";
+          return false;
+        }
+
+        // Type chunks must be preceded by their TypeSpec chunks.
+        if (!types_builder || type->id - 1 != last_type_idx) {
+          LOG(ERROR) << "Found RES_TABLE_TYPE_TYPE chunk without "
+                        "RES_TABLE_TYPE_SPEC_TYPE.";
+          return false;
+        }
+
+        if (!VerifyType(child_chunk)) {
+          return false;
+        }
+
+        types_builder->AddType(type);
+      } break;
+
+      default:
+        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        break;
+    }
+  }
+
+  // Finish the last TypeSpec.
+  if (types_builder) {
+    TypeSpecPtr type_spec_ptr = types_builder->Build();
+    if (type_spec_ptr == nullptr) {
+      LOG(ERROR) << "Too many type configurations, overflow detected.";
+      return false;
+    }
+    loaded_package->type_specs_.editItemAt(last_type_idx) = std::move(type_spec_ptr);
+  }
+
+  if (iter.HadError()) {
+    LOG(ERROR) << iter.GetLastError();
+    return false;
+  }
+  return true;
+}
+
+bool LoadedArsc::LoadTable(const Chunk& chunk) {
+  ATRACE_CALL();
+  const ResTable_header* header = chunk.header<ResTable_header>();
+  if (header == nullptr) {
+    LOG(ERROR) << "Chunk RES_TABLE_TYPE is too small.";
+    return false;
+  }
+
+  const size_t package_count = dtohl(header->packageCount);
+  size_t packages_seen = 0;
+
+  packages_.reserve(package_count);
+
+  ChunkIterator iter(chunk.data_ptr(), chunk.data_size());
+  while (iter.HasNext()) {
+    const Chunk child_chunk = iter.Next();
+    switch (child_chunk.type()) {
+      case RES_STRING_POOL_TYPE:
+        // Only use the first string pool. Ignore others.
+        if (global_string_pool_.getError() == NO_INIT) {
+          status_t err = global_string_pool_.setTo(child_chunk.header<ResStringPool_header>(),
+                                                   child_chunk.size());
+          if (err != NO_ERROR) {
+            LOG(ERROR) << "Corrupt string pool.";
+            return false;
+          }
+        } else {
+          LOG(WARNING) << "Multiple string pool chunks found in resource table.";
+        }
+        break;
+
+      case RES_TABLE_PACKAGE_TYPE: {
+        if (packages_seen + 1 > package_count) {
+          LOG(ERROR) << "More package chunks were found than the " << package_count
+                     << " declared in the "
+                        "header.";
+          return false;
+        }
+        packages_seen++;
+
+        std::unique_ptr<LoadedPackage> loaded_package = util::make_unique<LoadedPackage>();
+        if (!LoadPackage(child_chunk, loaded_package.get())) {
+          return false;
+        }
+        packages_.push_back(std::move(loaded_package));
+      } break;
+
+      default:
+        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        break;
+    }
+  }
+
+  if (iter.HadError()) {
+    LOG(ERROR) << iter.GetLastError();
+    return false;
+  }
+  return true;
+}
+
+std::unique_ptr<LoadedArsc> LoadedArsc::Load(const void* data, size_t len) {
+  ATRACE_CALL();
+
+  // Not using make_unique because the constructor is private.
+  std::unique_ptr<LoadedArsc> loaded_arsc(new LoadedArsc());
+
+  ChunkIterator iter(data, len);
+  while (iter.HasNext()) {
+    const Chunk chunk = iter.Next();
+    switch (chunk.type()) {
+      case RES_TABLE_TYPE:
+        if (!loaded_arsc->LoadTable(chunk)) {
+          return {};
+        }
+        break;
+
+      default:
+        LOG(WARNING) << base::StringPrintf("Unknown chunk type '%02x'.", chunk.type());
+        break;
+    }
+  }
+
+  if (iter.HadError()) {
+    LOG(ERROR) << iter.GetLastError();
+    return {};
+  }
+  return loaded_arsc;
+}
+
+}  // namespace android
diff --git a/libs/androidfw/LocaleDataTables.cpp b/libs/androidfw/LocaleDataTables.cpp
index 1ac5085..7c381ef 100644
--- a/libs/androidfw/LocaleDataTables.cpp
+++ b/libs/androidfw/LocaleDataTables.cpp
@@ -1,4 +1,4 @@
-// Auto-generated by frameworks/base/tools/localedata/extract_icu_data.py
+// Auto-generated by ./tools/localedata/extract_icu_data.py
 
 const char SCRIPT_CODES[][4] = {
     /* 0  */ {'A', 'h', 'o', 'm'},
@@ -39,27 +39,27 @@
     /* 35 */ {'K', 'h', 'm', 'r'},
     /* 36 */ {'K', 'n', 'd', 'a'},
     /* 37 */ {'K', 'o', 'r', 'e'},
-    /* 38 */ {'K', 't', 'h', 'i'},
-    /* 39 */ {'L', 'a', 'n', 'a'},
-    /* 40 */ {'L', 'a', 'o', 'o'},
-    /* 41 */ {'L', 'a', 't', 'n'},
-    /* 42 */ {'L', 'e', 'p', 'c'},
-    /* 43 */ {'L', 'i', 'n', 'a'},
-    /* 44 */ {'L', 'i', 's', 'u'},
-    /* 45 */ {'L', 'y', 'c', 'i'},
-    /* 46 */ {'L', 'y', 'd', 'i'},
-    /* 47 */ {'M', 'a', 'n', 'd'},
-    /* 48 */ {'M', 'a', 'n', 'i'},
-    /* 49 */ {'M', 'e', 'r', 'c'},
-    /* 50 */ {'M', 'l', 'y', 'm'},
-    /* 51 */ {'M', 'o', 'n', 'g'},
-    /* 52 */ {'M', 'r', 'o', 'o'},
-    /* 53 */ {'M', 'y', 'm', 'r'},
-    /* 54 */ {'N', 'a', 'r', 'b'},
-    /* 55 */ {'N', 'k', 'o', 'o'},
-    /* 56 */ {'O', 'g', 'a', 'm'},
-    /* 57 */ {'O', 'r', 'k', 'h'},
-    /* 58 */ {'O', 'r', 'y', 'a'},
+    /* 38 */ {'L', 'a', 'n', 'a'},
+    /* 39 */ {'L', 'a', 'o', 'o'},
+    /* 40 */ {'L', 'a', 't', 'n'},
+    /* 41 */ {'L', 'e', 'p', 'c'},
+    /* 42 */ {'L', 'i', 'n', 'a'},
+    /* 43 */ {'L', 'i', 's', 'u'},
+    /* 44 */ {'L', 'y', 'c', 'i'},
+    /* 45 */ {'L', 'y', 'd', 'i'},
+    /* 46 */ {'M', 'a', 'n', 'd'},
+    /* 47 */ {'M', 'a', 'n', 'i'},
+    /* 48 */ {'M', 'e', 'r', 'c'},
+    /* 49 */ {'M', 'l', 'y', 'm'},
+    /* 50 */ {'M', 'o', 'n', 'g'},
+    /* 51 */ {'M', 'r', 'o', 'o'},
+    /* 52 */ {'M', 'y', 'm', 'r'},
+    /* 53 */ {'N', 'a', 'r', 'b'},
+    /* 54 */ {'N', 'k', 'o', 'o'},
+    /* 55 */ {'O', 'g', 'a', 'm'},
+    /* 56 */ {'O', 'r', 'k', 'h'},
+    /* 57 */ {'O', 'r', 'y', 'a'},
+    /* 58 */ {'O', 's', 'g', 'e'},
     /* 59 */ {'P', 'a', 'u', 'c'},
     /* 60 */ {'P', 'h', 'l', 'i'},
     /* 61 */ {'P', 'h', 'n', 'x'},
@@ -76,78 +76,147 @@
     /* 72 */ {'T', 'a', 'l', 'e'},
     /* 73 */ {'T', 'a', 'l', 'u'},
     /* 74 */ {'T', 'a', 'm', 'l'},
-    /* 75 */ {'T', 'a', 'v', 't'},
-    /* 76 */ {'T', 'e', 'l', 'u'},
-    /* 77 */ {'T', 'f', 'n', 'g'},
-    /* 78 */ {'T', 'h', 'a', 'a'},
-    /* 79 */ {'T', 'h', 'a', 'i'},
-    /* 80 */ {'T', 'i', 'b', 't'},
-    /* 81 */ {'U', 'g', 'a', 'r'},
-    /* 82 */ {'V', 'a', 'i', 'i'},
-    /* 83 */ {'X', 'p', 'e', 'o'},
-    /* 84 */ {'X', 's', 'u', 'x'},
-    /* 85 */ {'Y', 'i', 'i', 'i'},
-    /* 86 */ {'~', '~', '~', 'A'},
-    /* 87 */ {'~', '~', '~', 'B'},
+    /* 75 */ {'T', 'a', 'n', 'g'},
+    /* 76 */ {'T', 'a', 'v', 't'},
+    /* 77 */ {'T', 'e', 'l', 'u'},
+    /* 78 */ {'T', 'f', 'n', 'g'},
+    /* 79 */ {'T', 'h', 'a', 'a'},
+    /* 80 */ {'T', 'h', 'a', 'i'},
+    /* 81 */ {'T', 'i', 'b', 't'},
+    /* 82 */ {'U', 'g', 'a', 'r'},
+    /* 83 */ {'V', 'a', 'i', 'i'},
+    /* 84 */ {'X', 'p', 'e', 'o'},
+    /* 85 */ {'X', 's', 'u', 'x'},
+    /* 86 */ {'Y', 'i', 'i', 'i'},
+    /* 87 */ {'~', '~', '~', 'A'},
+    /* 88 */ {'~', '~', '~', 'B'},
 };
 
 
 const std::unordered_map<uint32_t, uint8_t> LIKELY_SCRIPTS({
-    {0x61610000u, 41u}, // aa -> Latn
+    {0x61610000u, 40u}, // aa -> Latn
+    {0xA0000000u, 40u}, // aai -> Latn
+    {0xA8000000u, 40u}, // aak -> Latn
+    {0xD0000000u, 40u}, // aau -> Latn
     {0x61620000u, 15u}, // ab -> Cyrl
-    {0xC4200000u, 41u}, // abr -> Latn
-    {0x90400000u, 41u}, // ace -> Latn
-    {0x9C400000u, 41u}, // ach -> Latn
-    {0x80600000u, 41u}, // ada -> Latn
+    {0xA0200000u, 40u}, // abi -> Latn
+    {0xC4200000u, 40u}, // abr -> Latn
+    {0xCC200000u, 40u}, // abt -> Latn
+    {0xE0200000u, 40u}, // aby -> Latn
+    {0x8C400000u, 40u}, // acd -> Latn
+    {0x90400000u, 40u}, // ace -> Latn
+    {0x9C400000u, 40u}, // ach -> Latn
+    {0x80600000u, 40u}, // ada -> Latn
+    {0x90600000u, 40u}, // ade -> Latn
+    {0xA4600000u, 40u}, // adj -> Latn
     {0xE0600000u, 15u}, // ady -> Cyrl
+    {0xE4600000u, 40u}, // adz -> Latn
     {0x61650000u,  4u}, // ae -> Avst
     {0x84800000u,  1u}, // aeb -> Arab
-    {0x61660000u, 41u}, // af -> Latn
-    {0xC0C00000u, 41u}, // agq -> Latn
+    {0xE0800000u, 40u}, // aey -> Latn
+    {0x61660000u, 40u}, // af -> Latn
+    {0x88C00000u, 40u}, // agc -> Latn
+    {0x8CC00000u, 40u}, // agd -> Latn
+    {0x98C00000u, 40u}, // agg -> Latn
+    {0xB0C00000u, 40u}, // agm -> Latn
+    {0xB8C00000u, 40u}, // ago -> Latn
+    {0xC0C00000u, 40u}, // agq -> Latn
+    {0x80E00000u, 40u}, // aha -> Latn
+    {0xACE00000u, 40u}, // ahl -> Latn
     {0xB8E00000u,  0u}, // aho -> Ahom
-    {0x616B0000u, 41u}, // ak -> Latn
-    {0xA9400000u, 84u}, // akk -> Xsux
-    {0xB5600000u, 41u}, // aln -> Latn
+    {0x99200000u, 40u}, // ajg -> Latn
+    {0x616B0000u, 40u}, // ak -> Latn
+    {0xA9400000u, 85u}, // akk -> Xsux
+    {0x81600000u, 40u}, // ala -> Latn
+    {0xA1600000u, 40u}, // ali -> Latn
+    {0xB5600000u, 40u}, // aln -> Latn
     {0xCD600000u, 15u}, // alt -> Cyrl
     {0x616D0000u, 18u}, // am -> Ethi
-    {0xB9800000u, 41u}, // amo -> Latn
-    {0xE5C00000u, 41u}, // aoz -> Latn
+    {0xB1800000u, 40u}, // amm -> Latn
+    {0xB5800000u, 40u}, // amn -> Latn
+    {0xB9800000u, 40u}, // amo -> Latn
+    {0xBD800000u, 40u}, // amp -> Latn
+    {0x89A00000u, 40u}, // anc -> Latn
+    {0xA9A00000u, 40u}, // ank -> Latn
+    {0xB5A00000u, 40u}, // ann -> Latn
+    {0xE1A00000u, 40u}, // any -> Latn
+    {0xA5C00000u, 40u}, // aoj -> Latn
+    {0xB1C00000u, 40u}, // aom -> Latn
+    {0xE5C00000u, 40u}, // aoz -> Latn
+    {0x89E00000u,  1u}, // apc -> Arab
+    {0x8DE00000u,  1u}, // apd -> Arab
+    {0x91E00000u, 40u}, // ape -> Latn
+    {0xC5E00000u, 40u}, // apr -> Latn
+    {0xC9E00000u, 40u}, // aps -> Latn
+    {0xE5E00000u, 40u}, // apz -> Latn
     {0x61720000u,  1u}, // ar -> Arab
-    {0x61725842u, 87u}, // ar-XB -> ~~~B
+    {0x61725842u, 88u}, // ar-XB -> ~~~B
     {0x8A200000u,  2u}, // arc -> Armi
-    {0xB6200000u, 41u}, // arn -> Latn
-    {0xBA200000u, 41u}, // aro -> Latn
+    {0x9E200000u, 40u}, // arh -> Latn
+    {0xB6200000u, 40u}, // arn -> Latn
+    {0xBA200000u, 40u}, // aro -> Latn
     {0xC2200000u,  1u}, // arq -> Arab
     {0xE2200000u,  1u}, // ary -> Arab
     {0xE6200000u,  1u}, // arz -> Arab
     {0x61730000u,  7u}, // as -> Beng
-    {0x82400000u, 41u}, // asa -> Latn
+    {0x82400000u, 40u}, // asa -> Latn
     {0x92400000u, 68u}, // ase -> Sgnw
-    {0xCE400000u, 41u}, // ast -> Latn
-    {0xA6600000u, 41u}, // atj -> Latn
+    {0x9A400000u, 40u}, // asg -> Latn
+    {0xBA400000u, 40u}, // aso -> Latn
+    {0xCE400000u, 40u}, // ast -> Latn
+    {0x82600000u, 40u}, // ata -> Latn
+    {0x9A600000u, 40u}, // atg -> Latn
+    {0xA6600000u, 40u}, // atj -> Latn
+    {0xE2800000u, 40u}, // auy -> Latn
     {0x61760000u, 15u}, // av -> Cyrl
+    {0xAEA00000u,  1u}, // avl -> Arab
+    {0xB6A00000u, 40u}, // avn -> Latn
+    {0xCEA00000u, 40u}, // avt -> Latn
+    {0xD2A00000u, 40u}, // avu -> Latn
     {0x82C00000u, 16u}, // awa -> Deva
-    {0x61790000u, 41u}, // ay -> Latn
-    {0x617A0000u, 41u}, // az -> Latn
+    {0x86C00000u, 40u}, // awb -> Latn
+    {0xBAC00000u, 40u}, // awo -> Latn
+    {0xDEC00000u, 40u}, // awx -> Latn
+    {0x61790000u, 40u}, // ay -> Latn
+    {0x87000000u, 40u}, // ayb -> Latn
+    {0x617A0000u, 40u}, // az -> Latn
     {0x617A4951u,  1u}, // az-IQ -> Arab
     {0x617A4952u,  1u}, // az-IR -> Arab
     {0x617A5255u, 15u}, // az-RU -> Cyrl
     {0x62610000u, 15u}, // ba -> Cyrl
     {0xAC010000u,  1u}, // bal -> Arab
-    {0xB4010000u, 41u}, // ban -> Latn
+    {0xB4010000u, 40u}, // ban -> Latn
     {0xBC010000u, 16u}, // bap -> Deva
-    {0xC4010000u, 41u}, // bar -> Latn
-    {0xC8010000u, 41u}, // bas -> Latn
+    {0xC4010000u, 40u}, // bar -> Latn
+    {0xC8010000u, 40u}, // bas -> Latn
+    {0xD4010000u, 40u}, // bav -> Latn
     {0xDC010000u,  5u}, // bax -> Bamu
-    {0x88210000u, 41u}, // bbc -> Latn
-    {0xA4210000u, 41u}, // bbj -> Latn
-    {0xA0410000u, 41u}, // bci -> Latn
+    {0x80210000u, 40u}, // bba -> Latn
+    {0x84210000u, 40u}, // bbb -> Latn
+    {0x88210000u, 40u}, // bbc -> Latn
+    {0x8C210000u, 40u}, // bbd -> Latn
+    {0xA4210000u, 40u}, // bbj -> Latn
+    {0xBC210000u, 40u}, // bbp -> Latn
+    {0xC4210000u, 40u}, // bbr -> Latn
+    {0x94410000u, 40u}, // bcf -> Latn
+    {0x9C410000u, 40u}, // bch -> Latn
+    {0xA0410000u, 40u}, // bci -> Latn
+    {0xB0410000u, 40u}, // bcm -> Latn
+    {0xB4410000u, 40u}, // bcn -> Latn
+    {0xB8410000u, 40u}, // bco -> Latn
+    {0xC0410000u, 18u}, // bcq -> Ethi
+    {0xD0410000u, 40u}, // bcu -> Latn
+    {0x8C610000u, 40u}, // bdd -> Latn
     {0x62650000u, 15u}, // be -> Cyrl
+    {0x94810000u, 40u}, // bef -> Latn
+    {0x9C810000u, 40u}, // beh -> Latn
     {0xA4810000u,  1u}, // bej -> Arab
-    {0xB0810000u, 41u}, // bem -> Latn
-    {0xD8810000u, 41u}, // bew -> Latn
-    {0xE4810000u, 41u}, // bez -> Latn
-    {0x8CA10000u, 41u}, // bfd -> Latn
+    {0xB0810000u, 40u}, // bem -> Latn
+    {0xCC810000u, 40u}, // bet -> Latn
+    {0xD8810000u, 40u}, // bew -> Latn
+    {0xDC810000u, 40u}, // bex -> Latn
+    {0xE4810000u, 40u}, // bez -> Latn
+    {0x8CA10000u, 40u}, // bfd -> Latn
     {0xC0A10000u, 74u}, // bfq -> Taml
     {0xCCA10000u,  1u}, // bft -> Arab
     {0xE0A10000u, 16u}, // bfy -> Deva
@@ -155,663 +224,1202 @@
     {0x88C10000u, 16u}, // bgc -> Deva
     {0xB4C10000u,  1u}, // bgn -> Arab
     {0xDCC10000u, 21u}, // bgx -> Grek
-    {0x62680000u, 38u}, // bh -> Kthi
     {0x84E10000u, 16u}, // bhb -> Deva
+    {0x98E10000u, 40u}, // bhg -> Latn
     {0xA0E10000u, 16u}, // bhi -> Deva
-    {0xA8E10000u, 41u}, // bhk -> Latn
+    {0xA8E10000u, 40u}, // bhk -> Latn
+    {0xACE10000u, 40u}, // bhl -> Latn
     {0xB8E10000u, 16u}, // bho -> Deva
-    {0x62690000u, 41u}, // bi -> Latn
-    {0xA9010000u, 41u}, // bik -> Latn
-    {0xB5010000u, 41u}, // bin -> Latn
+    {0xE0E10000u, 40u}, // bhy -> Latn
+    {0x62690000u, 40u}, // bi -> Latn
+    {0x85010000u, 40u}, // bib -> Latn
+    {0x99010000u, 40u}, // big -> Latn
+    {0xA9010000u, 40u}, // bik -> Latn
+    {0xB1010000u, 40u}, // bim -> Latn
+    {0xB5010000u, 40u}, // bin -> Latn
+    {0xB9010000u, 40u}, // bio -> Latn
+    {0xC1010000u, 40u}, // biq -> Latn
+    {0x9D210000u, 40u}, // bjh -> Latn
+    {0xA1210000u, 18u}, // bji -> Ethi
     {0xA5210000u, 16u}, // bjj -> Deva
-    {0xB5210000u, 41u}, // bjn -> Latn
-    {0xB1410000u, 41u}, // bkm -> Latn
-    {0xD1410000u, 41u}, // bku -> Latn
-    {0xCD610000u, 75u}, // blt -> Tavt
-    {0x626D0000u, 41u}, // bm -> Latn
-    {0xC1810000u, 41u}, // bmq -> Latn
+    {0xB5210000u, 40u}, // bjn -> Latn
+    {0xB9210000u, 40u}, // bjo -> Latn
+    {0xC5210000u, 40u}, // bjr -> Latn
+    {0xE5210000u, 40u}, // bjz -> Latn
+    {0x89410000u, 40u}, // bkc -> Latn
+    {0xB1410000u, 40u}, // bkm -> Latn
+    {0xC1410000u, 40u}, // bkq -> Latn
+    {0xD1410000u, 40u}, // bku -> Latn
+    {0xD5410000u, 40u}, // bkv -> Latn
+    {0xCD610000u, 76u}, // blt -> Tavt
+    {0x626D0000u, 40u}, // bm -> Latn
+    {0x9D810000u, 40u}, // bmh -> Latn
+    {0xA9810000u, 40u}, // bmk -> Latn
+    {0xC1810000u, 40u}, // bmq -> Latn
+    {0xD1810000u, 40u}, // bmu -> Latn
     {0x626E0000u,  7u}, // bn -> Beng
-    {0x626F0000u, 80u}, // bo -> Tibt
+    {0x99A10000u, 40u}, // bng -> Latn
+    {0xB1A10000u, 40u}, // bnm -> Latn
+    {0xBDA10000u, 40u}, // bnp -> Latn
+    {0x626F0000u, 81u}, // bo -> Tibt
+    {0xA5C10000u, 40u}, // boj -> Latn
+    {0xB1C10000u, 40u}, // bom -> Latn
+    {0xB5C10000u, 40u}, // bon -> Latn
     {0xE1E10000u,  7u}, // bpy -> Beng
+    {0x8A010000u, 40u}, // bqc -> Latn
     {0xA2010000u,  1u}, // bqi -> Arab
-    {0xD6010000u, 41u}, // bqv -> Latn
-    {0x62720000u, 41u}, // br -> Latn
+    {0xBE010000u, 40u}, // bqp -> Latn
+    {0xD6010000u, 40u}, // bqv -> Latn
+    {0x62720000u, 40u}, // br -> Latn
     {0x82210000u, 16u}, // bra -> Deva
     {0x9E210000u,  1u}, // brh -> Arab
     {0xDE210000u, 16u}, // brx -> Deva
-    {0x62730000u, 41u}, // bs -> Latn
+    {0xE6210000u, 40u}, // brz -> Latn
+    {0x62730000u, 40u}, // bs -> Latn
+    {0xA6410000u, 40u}, // bsj -> Latn
     {0xC2410000u,  6u}, // bsq -> Bass
-    {0xCA410000u, 41u}, // bss -> Latn
-    {0xBA610000u, 41u}, // bto -> Latn
+    {0xCA410000u, 40u}, // bss -> Latn
+    {0xCE410000u, 18u}, // bst -> Ethi
+    {0xBA610000u, 40u}, // bto -> Latn
+    {0xCE610000u, 40u}, // btt -> Latn
     {0xD6610000u, 16u}, // btv -> Deva
     {0x82810000u, 15u}, // bua -> Cyrl
-    {0x8A810000u, 41u}, // buc -> Latn
-    {0x9A810000u, 41u}, // bug -> Latn
-    {0xB2810000u, 41u}, // bum -> Latn
-    {0x86A10000u, 41u}, // bvb -> Latn
+    {0x8A810000u, 40u}, // buc -> Latn
+    {0x8E810000u, 40u}, // bud -> Latn
+    {0x9A810000u, 40u}, // bug -> Latn
+    {0xAA810000u, 40u}, // buk -> Latn
+    {0xB2810000u, 40u}, // bum -> Latn
+    {0xBA810000u, 40u}, // buo -> Latn
+    {0xCA810000u, 40u}, // bus -> Latn
+    {0xD2810000u, 40u}, // buu -> Latn
+    {0x86A10000u, 40u}, // bvb -> Latn
+    {0x8EC10000u, 40u}, // bwd -> Latn
+    {0xC6C10000u, 40u}, // bwr -> Latn
+    {0x9EE10000u, 40u}, // bxh -> Latn
+    {0x93010000u, 40u}, // bye -> Latn
     {0xB7010000u, 18u}, // byn -> Ethi
-    {0xD7010000u, 41u}, // byv -> Latn
-    {0x93210000u, 41u}, // bze -> Latn
-    {0x63610000u, 41u}, // ca -> Latn
-    {0x9C420000u, 41u}, // cch -> Latn
+    {0xC7010000u, 40u}, // byr -> Latn
+    {0xCB010000u, 40u}, // bys -> Latn
+    {0xD7010000u, 40u}, // byv -> Latn
+    {0xDF010000u, 40u}, // byx -> Latn
+    {0x83210000u, 40u}, // bza -> Latn
+    {0x93210000u, 40u}, // bze -> Latn
+    {0x97210000u, 40u}, // bzf -> Latn
+    {0x9F210000u, 40u}, // bzh -> Latn
+    {0xDB210000u, 40u}, // bzw -> Latn
+    {0x63610000u, 40u}, // ca -> Latn
+    {0xB4020000u, 40u}, // can -> Latn
+    {0xA4220000u, 40u}, // cbj -> Latn
+    {0x9C420000u, 40u}, // cch -> Latn
     {0xBC420000u,  7u}, // ccp -> Beng
     {0x63650000u, 15u}, // ce -> Cyrl
-    {0x84820000u, 41u}, // ceb -> Latn
-    {0x98C20000u, 41u}, // cgg -> Latn
-    {0x63680000u, 41u}, // ch -> Latn
-    {0xA8E20000u, 41u}, // chk -> Latn
+    {0x84820000u, 40u}, // ceb -> Latn
+    {0x80A20000u, 40u}, // cfa -> Latn
+    {0x98C20000u, 40u}, // cgg -> Latn
+    {0x63680000u, 40u}, // ch -> Latn
+    {0xA8E20000u, 40u}, // chk -> Latn
     {0xB0E20000u, 15u}, // chm -> Cyrl
-    {0xB8E20000u, 41u}, // cho -> Latn
-    {0xBCE20000u, 41u}, // chp -> Latn
+    {0xB8E20000u, 40u}, // cho -> Latn
+    {0xBCE20000u, 40u}, // chp -> Latn
     {0xC4E20000u, 12u}, // chr -> Cher
     {0x81220000u,  1u}, // cja -> Arab
     {0xB1220000u, 11u}, // cjm -> Cham
+    {0xD5220000u, 40u}, // cjv -> Latn
     {0x85420000u,  1u}, // ckb -> Arab
-    {0x636F0000u, 41u}, // co -> Latn
+    {0xAD420000u, 40u}, // ckl -> Latn
+    {0xB9420000u, 40u}, // cko -> Latn
+    {0xE1420000u, 40u}, // cky -> Latn
+    {0x81620000u, 40u}, // cla -> Latn
+    {0x91820000u, 40u}, // cme -> Latn
+    {0x636F0000u, 40u}, // co -> Latn
     {0xBDC20000u, 13u}, // cop -> Copt
-    {0xC9E20000u, 41u}, // cps -> Latn
+    {0xC9E20000u, 40u}, // cps -> Latn
     {0x63720000u,  9u}, // cr -> Cans
     {0xA6220000u,  9u}, // crj -> Cans
     {0xAA220000u,  9u}, // crk -> Cans
     {0xAE220000u,  9u}, // crl -> Cans
     {0xB2220000u,  9u}, // crm -> Cans
-    {0xCA220000u, 41u}, // crs -> Latn
-    {0x63730000u, 41u}, // cs -> Latn
-    {0x86420000u, 41u}, // csb -> Latn
+    {0xCA220000u, 40u}, // crs -> Latn
+    {0x63730000u, 40u}, // cs -> Latn
+    {0x86420000u, 40u}, // csb -> Latn
     {0xDA420000u,  9u}, // csw -> Cans
     {0x8E620000u, 59u}, // ctd -> Pauc
     {0x63750000u, 15u}, // cu -> Cyrl
     {0x63760000u, 15u}, // cv -> Cyrl
-    {0x63790000u, 41u}, // cy -> Latn
-    {0x64610000u, 41u}, // da -> Latn
-    {0xA8030000u, 41u}, // dak -> Latn
+    {0x63790000u, 40u}, // cy -> Latn
+    {0x64610000u, 40u}, // da -> Latn
+    {0x8C030000u, 40u}, // dad -> Latn
+    {0x94030000u, 40u}, // daf -> Latn
+    {0x98030000u, 40u}, // dag -> Latn
+    {0x9C030000u, 40u}, // dah -> Latn
+    {0xA8030000u, 40u}, // dak -> Latn
     {0xC4030000u, 15u}, // dar -> Cyrl
-    {0xD4030000u, 41u}, // dav -> Latn
+    {0xD4030000u, 40u}, // dav -> Latn
+    {0x8C230000u, 40u}, // dbd -> Latn
+    {0xC0230000u, 40u}, // dbq -> Latn
     {0x88430000u,  1u}, // dcc -> Arab
-    {0x64650000u, 41u}, // de -> Latn
-    {0xB4830000u, 41u}, // den -> Latn
-    {0xC4C30000u, 41u}, // dgr -> Latn
-    {0x91230000u, 41u}, // dje -> Latn
-    {0xA5A30000u, 41u}, // dnj -> Latn
+    {0xB4630000u, 40u}, // ddn -> Latn
+    {0x64650000u, 40u}, // de -> Latn
+    {0x8C830000u, 40u}, // ded -> Latn
+    {0xB4830000u, 40u}, // den -> Latn
+    {0x80C30000u, 40u}, // dga -> Latn
+    {0x9CC30000u, 40u}, // dgh -> Latn
+    {0xA0C30000u, 40u}, // dgi -> Latn
+    {0xACC30000u,  1u}, // dgl -> Arab
+    {0xC4C30000u, 40u}, // dgr -> Latn
+    {0xE4C30000u, 40u}, // dgz -> Latn
+    {0x81030000u, 40u}, // dia -> Latn
+    {0x91230000u, 40u}, // dje -> Latn
+    {0xA5A30000u, 40u}, // dnj -> Latn
+    {0x85C30000u, 40u}, // dob -> Latn
     {0xA1C30000u,  1u}, // doi -> Arab
-    {0x86430000u, 41u}, // dsb -> Latn
-    {0xB2630000u, 41u}, // dtm -> Latn
-    {0xBE630000u, 41u}, // dtp -> Latn
-    {0x82830000u, 41u}, // dua -> Latn
-    {0x64760000u, 78u}, // dv -> Thaa
-    {0xBB030000u, 41u}, // dyo -> Latn
-    {0xD3030000u, 41u}, // dyu -> Latn
-    {0x647A0000u, 80u}, // dz -> Tibt
-    {0xD0240000u, 41u}, // ebu -> Latn
-    {0x65650000u, 41u}, // ee -> Latn
-    {0xA0A40000u, 41u}, // efi -> Latn
-    {0xACC40000u, 41u}, // egl -> Latn
+    {0xBDC30000u, 40u}, // dop -> Latn
+    {0xD9C30000u, 40u}, // dow -> Latn
+    {0xA2230000u, 40u}, // dri -> Latn
+    {0xCA230000u, 18u}, // drs -> Ethi
+    {0x86430000u, 40u}, // dsb -> Latn
+    {0xB2630000u, 40u}, // dtm -> Latn
+    {0xBE630000u, 40u}, // dtp -> Latn
+    {0xCA630000u, 40u}, // dts -> Latn
+    {0xE2630000u, 16u}, // dty -> Deva
+    {0x82830000u, 40u}, // dua -> Latn
+    {0x8A830000u, 40u}, // duc -> Latn
+    {0x8E830000u, 40u}, // dud -> Latn
+    {0x9A830000u, 40u}, // dug -> Latn
+    {0x64760000u, 79u}, // dv -> Thaa
+    {0x82A30000u, 40u}, // dva -> Latn
+    {0xDAC30000u, 40u}, // dww -> Latn
+    {0xBB030000u, 40u}, // dyo -> Latn
+    {0xD3030000u, 40u}, // dyu -> Latn
+    {0x647A0000u, 81u}, // dz -> Tibt
+    {0x9B230000u, 40u}, // dzg -> Latn
+    {0xD0240000u, 40u}, // ebu -> Latn
+    {0x65650000u, 40u}, // ee -> Latn
+    {0xA0A40000u, 40u}, // efi -> Latn
+    {0xACC40000u, 40u}, // egl -> Latn
     {0xE0C40000u, 17u}, // egy -> Egyp
     {0xE1440000u, 32u}, // eky -> Kali
     {0x656C0000u, 21u}, // el -> Grek
-    {0x656E0000u, 41u}, // en -> Latn
-    {0x656E5841u, 86u}, // en-XA -> ~~~A
-    {0x656F0000u, 41u}, // eo -> Latn
-    {0x65730000u, 41u}, // es -> Latn
-    {0xD2440000u, 41u}, // esu -> Latn
-    {0x65740000u, 41u}, // et -> Latn
+    {0x81840000u, 40u}, // ema -> Latn
+    {0xA1840000u, 40u}, // emi -> Latn
+    {0x656E0000u, 40u}, // en -> Latn
+    {0x656E5841u, 87u}, // en-XA -> ~~~A
+    {0xB5A40000u, 40u}, // enn -> Latn
+    {0xC1A40000u, 40u}, // enq -> Latn
+    {0x656F0000u, 40u}, // eo -> Latn
+    {0xA2240000u, 40u}, // eri -> Latn
+    {0x65730000u, 40u}, // es -> Latn
+    {0xD2440000u, 40u}, // esu -> Latn
+    {0x65740000u, 40u}, // et -> Latn
+    {0xC6640000u, 40u}, // etr -> Latn
     {0xCE640000u, 30u}, // ett -> Ital
-    {0x65750000u, 41u}, // eu -> Latn
-    {0xBAC40000u, 41u}, // ewo -> Latn
-    {0xCEE40000u, 41u}, // ext -> Latn
+    {0xD2640000u, 40u}, // etu -> Latn
+    {0xDE640000u, 40u}, // etx -> Latn
+    {0x65750000u, 40u}, // eu -> Latn
+    {0xBAC40000u, 40u}, // ewo -> Latn
+    {0xCEE40000u, 40u}, // ext -> Latn
     {0x66610000u,  1u}, // fa -> Arab
-    {0xB4050000u, 41u}, // fan -> Latn
-    {0x66660000u, 41u}, // ff -> Latn
-    {0xB0A50000u, 41u}, // ffm -> Latn
-    {0x66690000u, 41u}, // fi -> Latn
+    {0x80050000u, 40u}, // faa -> Latn
+    {0x84050000u, 40u}, // fab -> Latn
+    {0x98050000u, 40u}, // fag -> Latn
+    {0xA0050000u, 40u}, // fai -> Latn
+    {0xB4050000u, 40u}, // fan -> Latn
+    {0x66660000u, 40u}, // ff -> Latn
+    {0xA0A50000u, 40u}, // ffi -> Latn
+    {0xB0A50000u, 40u}, // ffm -> Latn
+    {0x66690000u, 40u}, // fi -> Latn
     {0x81050000u,  1u}, // fia -> Arab
-    {0xAD050000u, 41u}, // fil -> Latn
-    {0xCD050000u, 41u}, // fit -> Latn
-    {0x666A0000u, 41u}, // fj -> Latn
-    {0x666F0000u, 41u}, // fo -> Latn
-    {0xB5C50000u, 41u}, // fon -> Latn
-    {0x66720000u, 41u}, // fr -> Latn
-    {0x8A250000u, 41u}, // frc -> Latn
-    {0xBE250000u, 41u}, // frp -> Latn
-    {0xC6250000u, 41u}, // frr -> Latn
-    {0xCA250000u, 41u}, // frs -> Latn
-    {0x8E850000u, 41u}, // fud -> Latn
-    {0xC2850000u, 41u}, // fuq -> Latn
-    {0xC6850000u, 41u}, // fur -> Latn
-    {0xD6850000u, 41u}, // fuv -> Latn
-    {0xC6A50000u, 41u}, // fvr -> Latn
-    {0x66790000u, 41u}, // fy -> Latn
-    {0x67610000u, 41u}, // ga -> Latn
-    {0x80060000u, 41u}, // gaa -> Latn
-    {0x98060000u, 41u}, // gag -> Latn
+    {0xAD050000u, 40u}, // fil -> Latn
+    {0xCD050000u, 40u}, // fit -> Latn
+    {0x666A0000u, 40u}, // fj -> Latn
+    {0xC5650000u, 40u}, // flr -> Latn
+    {0xBD850000u, 40u}, // fmp -> Latn
+    {0x666F0000u, 40u}, // fo -> Latn
+    {0x8DC50000u, 40u}, // fod -> Latn
+    {0xB5C50000u, 40u}, // fon -> Latn
+    {0xC5C50000u, 40u}, // for -> Latn
+    {0x91E50000u, 40u}, // fpe -> Latn
+    {0xCA050000u, 40u}, // fqs -> Latn
+    {0x66720000u, 40u}, // fr -> Latn
+    {0x8A250000u, 40u}, // frc -> Latn
+    {0xBE250000u, 40u}, // frp -> Latn
+    {0xC6250000u, 40u}, // frr -> Latn
+    {0xCA250000u, 40u}, // frs -> Latn
+    {0x86850000u,  1u}, // fub -> Arab
+    {0x8E850000u, 40u}, // fud -> Latn
+    {0x92850000u, 40u}, // fue -> Latn
+    {0x96850000u, 40u}, // fuf -> Latn
+    {0x9E850000u, 40u}, // fuh -> Latn
+    {0xC2850000u, 40u}, // fuq -> Latn
+    {0xC6850000u, 40u}, // fur -> Latn
+    {0xD6850000u, 40u}, // fuv -> Latn
+    {0xE2850000u, 40u}, // fuy -> Latn
+    {0xC6A50000u, 40u}, // fvr -> Latn
+    {0x66790000u, 40u}, // fy -> Latn
+    {0x67610000u, 40u}, // ga -> Latn
+    {0x80060000u, 40u}, // gaa -> Latn
+    {0x94060000u, 40u}, // gaf -> Latn
+    {0x98060000u, 40u}, // gag -> Latn
+    {0x9C060000u, 40u}, // gah -> Latn
+    {0xA4060000u, 40u}, // gaj -> Latn
+    {0xB0060000u, 40u}, // gam -> Latn
     {0xB4060000u, 24u}, // gan -> Hans
-    {0xE0060000u, 41u}, // gay -> Latn
+    {0xD8060000u, 40u}, // gaw -> Latn
+    {0xE0060000u, 40u}, // gay -> Latn
+    {0x94260000u, 40u}, // gbf -> Latn
     {0xB0260000u, 16u}, // gbm -> Deva
+    {0xE0260000u, 40u}, // gby -> Latn
     {0xE4260000u,  1u}, // gbz -> Arab
-    {0xC4460000u, 41u}, // gcr -> Latn
-    {0x67640000u, 41u}, // gd -> Latn
+    {0xC4460000u, 40u}, // gcr -> Latn
+    {0x67640000u, 40u}, // gd -> Latn
+    {0x90660000u, 40u}, // gde -> Latn
+    {0xB4660000u, 40u}, // gdn -> Latn
+    {0xC4660000u, 40u}, // gdr -> Latn
+    {0x84860000u, 40u}, // geb -> Latn
+    {0xA4860000u, 40u}, // gej -> Latn
+    {0xAC860000u, 40u}, // gel -> Latn
     {0xE4860000u, 18u}, // gez -> Ethi
+    {0xA8A60000u, 40u}, // gfk -> Latn
     {0xB4C60000u, 16u}, // ggn -> Deva
-    {0xAD060000u, 41u}, // gil -> Latn
+    {0xC8E60000u, 40u}, // ghs -> Latn
+    {0xAD060000u, 40u}, // gil -> Latn
+    {0xB1060000u, 40u}, // gim -> Latn
     {0xA9260000u,  1u}, // gjk -> Arab
+    {0xB5260000u, 40u}, // gjn -> Latn
     {0xD1260000u,  1u}, // gju -> Arab
-    {0x676C0000u, 41u}, // gl -> Latn
+    {0xB5460000u, 40u}, // gkn -> Latn
+    {0xBD460000u, 40u}, // gkp -> Latn
+    {0x676C0000u, 40u}, // gl -> Latn
     {0xA9660000u,  1u}, // glk -> Arab
-    {0x676E0000u, 41u}, // gn -> Latn
+    {0xB1860000u, 40u}, // gmm -> Latn
+    {0xD5860000u, 18u}, // gmv -> Ethi
+    {0x676E0000u, 40u}, // gn -> Latn
+    {0x8DA60000u, 40u}, // gnd -> Latn
+    {0x99A60000u, 40u}, // gng -> Latn
+    {0x8DC60000u, 40u}, // god -> Latn
+    {0x95C60000u, 18u}, // gof -> Ethi
+    {0xA1C60000u, 40u}, // goi -> Latn
     {0xB1C60000u, 16u}, // gom -> Deva
-    {0xB5C60000u, 76u}, // gon -> Telu
-    {0xC5C60000u, 41u}, // gor -> Latn
-    {0xC9C60000u, 41u}, // gos -> Latn
+    {0xB5C60000u, 77u}, // gon -> Telu
+    {0xC5C60000u, 40u}, // gor -> Latn
+    {0xC9C60000u, 40u}, // gos -> Latn
     {0xCDC60000u, 20u}, // got -> Goth
     {0x8A260000u, 14u}, // grc -> Cprt
     {0xCE260000u,  7u}, // grt -> Beng
-    {0xDA460000u, 41u}, // gsw -> Latn
+    {0xDA260000u, 40u}, // grw -> Latn
+    {0xDA460000u, 40u}, // gsw -> Latn
     {0x67750000u, 22u}, // gu -> Gujr
-    {0x86860000u, 41u}, // gub -> Latn
-    {0x8A860000u, 41u}, // guc -> Latn
-    {0xC6860000u, 41u}, // gur -> Latn
-    {0xE6860000u, 41u}, // guz -> Latn
-    {0x67760000u, 41u}, // gv -> Latn
+    {0x86860000u, 40u}, // gub -> Latn
+    {0x8A860000u, 40u}, // guc -> Latn
+    {0x8E860000u, 40u}, // gud -> Latn
+    {0xC6860000u, 40u}, // gur -> Latn
+    {0xDA860000u, 40u}, // guw -> Latn
+    {0xDE860000u, 40u}, // gux -> Latn
+    {0xE6860000u, 40u}, // guz -> Latn
+    {0x67760000u, 40u}, // gv -> Latn
+    {0x96A60000u, 40u}, // gvf -> Latn
     {0xC6A60000u, 16u}, // gvr -> Deva
-    {0xA2C60000u, 41u}, // gwi -> Latn
-    {0x68610000u, 41u}, // ha -> Latn
+    {0xCAA60000u, 40u}, // gvs -> Latn
+    {0x8AC60000u,  1u}, // gwc -> Arab
+    {0xA2C60000u, 40u}, // gwi -> Latn
+    {0xCEC60000u,  1u}, // gwt -> Arab
+    {0xA3060000u, 40u}, // gyi -> Latn
+    {0x68610000u, 40u}, // ha -> Latn
     {0x6861434Du,  1u}, // ha-CM -> Arab
     {0x68615344u,  1u}, // ha-SD -> Arab
+    {0x98070000u, 40u}, // hag -> Latn
     {0xA8070000u, 24u}, // hak -> Hans
-    {0xD8070000u, 41u}, // haw -> Latn
+    {0xB0070000u, 40u}, // ham -> Latn
+    {0xD8070000u, 40u}, // haw -> Latn
     {0xE4070000u,  1u}, // haz -> Arab
+    {0x84270000u, 40u}, // hbb -> Latn
+    {0xE0670000u, 18u}, // hdy -> Ethi
     {0x68650000u, 27u}, // he -> Hebr
+    {0xE0E70000u, 40u}, // hhy -> Latn
     {0x68690000u, 16u}, // hi -> Deva
-    {0x95070000u, 41u}, // hif -> Latn
-    {0xAD070000u, 41u}, // hil -> Latn
+    {0x81070000u, 40u}, // hia -> Latn
+    {0x95070000u, 40u}, // hif -> Latn
+    {0x99070000u, 40u}, // hig -> Latn
+    {0x9D070000u, 40u}, // hih -> Latn
+    {0xAD070000u, 40u}, // hil -> Latn
+    {0x81670000u, 40u}, // hla -> Latn
     {0xD1670000u, 28u}, // hlu -> Hluw
     {0x8D870000u, 62u}, // hmd -> Plrd
+    {0xCD870000u, 40u}, // hmt -> Latn
     {0x8DA70000u,  1u}, // hnd -> Arab
     {0x91A70000u, 16u}, // hne -> Deva
     {0xA5A70000u, 29u}, // hnj -> Hmng
-    {0xB5A70000u, 41u}, // hnn -> Latn
+    {0xB5A70000u, 40u}, // hnn -> Latn
     {0xB9A70000u,  1u}, // hno -> Arab
-    {0x686F0000u, 41u}, // ho -> Latn
+    {0x686F0000u, 40u}, // ho -> Latn
     {0x89C70000u, 16u}, // hoc -> Deva
     {0xA5C70000u, 16u}, // hoj -> Deva
-    {0x68720000u, 41u}, // hr -> Latn
-    {0x86470000u, 41u}, // hsb -> Latn
+    {0xCDC70000u, 40u}, // hot -> Latn
+    {0x68720000u, 40u}, // hr -> Latn
+    {0x86470000u, 40u}, // hsb -> Latn
     {0xB6470000u, 24u}, // hsn -> Hans
-    {0x68740000u, 41u}, // ht -> Latn
-    {0x68750000u, 41u}, // hu -> Latn
+    {0x68740000u, 40u}, // ht -> Latn
+    {0x68750000u, 40u}, // hu -> Latn
+    {0xA2870000u, 40u}, // hui -> Latn
     {0x68790000u,  3u}, // hy -> Armn
-    {0x687A0000u, 41u}, // hz -> Latn
-    {0x69610000u, 41u}, // ia -> Latn
-    {0x80280000u, 41u}, // iba -> Latn
-    {0x84280000u, 41u}, // ibb -> Latn
-    {0x69640000u, 41u}, // id -> Latn
-    {0x69670000u, 41u}, // ig -> Latn
-    {0x69690000u, 85u}, // ii -> Yiii
-    {0x696B0000u, 41u}, // ik -> Latn
-    {0xCD480000u, 41u}, // ikt -> Latn
-    {0xB9680000u, 41u}, // ilo -> Latn
-    {0x696E0000u, 41u}, // in -> Latn
+    {0x687A0000u, 40u}, // hz -> Latn
+    {0x69610000u, 40u}, // ia -> Latn
+    {0xB4080000u, 40u}, // ian -> Latn
+    {0xC4080000u, 40u}, // iar -> Latn
+    {0x80280000u, 40u}, // iba -> Latn
+    {0x84280000u, 40u}, // ibb -> Latn
+    {0xE0280000u, 40u}, // iby -> Latn
+    {0x80480000u, 40u}, // ica -> Latn
+    {0x9C480000u, 40u}, // ich -> Latn
+    {0x69640000u, 40u}, // id -> Latn
+    {0x8C680000u, 40u}, // idd -> Latn
+    {0xA0680000u, 40u}, // idi -> Latn
+    {0xD0680000u, 40u}, // idu -> Latn
+    {0x69670000u, 40u}, // ig -> Latn
+    {0x84C80000u, 40u}, // igb -> Latn
+    {0x90C80000u, 40u}, // ige -> Latn
+    {0x69690000u, 86u}, // ii -> Yiii
+    {0xA5280000u, 40u}, // ijj -> Latn
+    {0x696B0000u, 40u}, // ik -> Latn
+    {0xA9480000u, 40u}, // ikk -> Latn
+    {0xCD480000u, 40u}, // ikt -> Latn
+    {0xD9480000u, 40u}, // ikw -> Latn
+    {0xDD480000u, 40u}, // ikx -> Latn
+    {0xB9680000u, 40u}, // ilo -> Latn
+    {0xB9880000u, 40u}, // imo -> Latn
+    {0x696E0000u, 40u}, // in -> Latn
     {0x9DA80000u, 15u}, // inh -> Cyrl
-    {0x69730000u, 41u}, // is -> Latn
-    {0x69740000u, 41u}, // it -> Latn
+    {0xD1C80000u, 40u}, // iou -> Latn
+    {0xA2280000u, 40u}, // iri -> Latn
+    {0x69730000u, 40u}, // is -> Latn
+    {0x69740000u, 40u}, // it -> Latn
     {0x69750000u,  9u}, // iu -> Cans
     {0x69770000u, 27u}, // iw -> Hebr
-    {0x9F280000u, 41u}, // izh -> Latn
+    {0xB2C80000u, 40u}, // iwm -> Latn
+    {0xCAC80000u, 40u}, // iws -> Latn
+    {0x9F280000u, 40u}, // izh -> Latn
+    {0xA3280000u, 40u}, // izi -> Latn
     {0x6A610000u, 31u}, // ja -> Jpan
-    {0xB0090000u, 41u}, // jam -> Latn
-    {0xB8C90000u, 41u}, // jgo -> Latn
+    {0x84090000u, 40u}, // jab -> Latn
+    {0xB0090000u, 40u}, // jam -> Latn
+    {0xD0290000u, 40u}, // jbu -> Latn
+    {0xB4890000u, 40u}, // jen -> Latn
+    {0xA8C90000u, 40u}, // jgk -> Latn
+    {0xB8C90000u, 40u}, // jgo -> Latn
     {0x6A690000u, 27u}, // ji -> Hebr
-    {0x89890000u, 41u}, // jmc -> Latn
+    {0x85090000u, 40u}, // jib -> Latn
+    {0x89890000u, 40u}, // jmc -> Latn
     {0xAD890000u, 16u}, // jml -> Deva
-    {0xCE890000u, 41u}, // jut -> Latn
-    {0x6A760000u, 41u}, // jv -> Latn
-    {0x6A770000u, 41u}, // jw -> Latn
+    {0x82290000u, 40u}, // jra -> Latn
+    {0xCE890000u, 40u}, // jut -> Latn
+    {0x6A760000u, 40u}, // jv -> Latn
+    {0x6A770000u, 40u}, // jw -> Latn
     {0x6B610000u, 19u}, // ka -> Geor
     {0x800A0000u, 15u}, // kaa -> Cyrl
-    {0x840A0000u, 41u}, // kab -> Latn
-    {0x880A0000u, 41u}, // kac -> Latn
-    {0xA40A0000u, 41u}, // kaj -> Latn
-    {0xB00A0000u, 41u}, // kam -> Latn
-    {0xB80A0000u, 41u}, // kao -> Latn
+    {0x840A0000u, 40u}, // kab -> Latn
+    {0x880A0000u, 40u}, // kac -> Latn
+    {0x8C0A0000u, 40u}, // kad -> Latn
+    {0xA00A0000u, 40u}, // kai -> Latn
+    {0xA40A0000u, 40u}, // kaj -> Latn
+    {0xB00A0000u, 40u}, // kam -> Latn
+    {0xB80A0000u, 40u}, // kao -> Latn
     {0x8C2A0000u, 15u}, // kbd -> Cyrl
-    {0x984A0000u, 41u}, // kcg -> Latn
-    {0xA84A0000u, 41u}, // kck -> Latn
-    {0x906A0000u, 41u}, // kde -> Latn
-    {0xCC6A0000u, 79u}, // kdt -> Thai
-    {0x808A0000u, 41u}, // kea -> Latn
-    {0xB48A0000u, 41u}, // ken -> Latn
-    {0xB8AA0000u, 41u}, // kfo -> Latn
+    {0xB02A0000u, 40u}, // kbm -> Latn
+    {0xBC2A0000u, 40u}, // kbp -> Latn
+    {0xC02A0000u, 40u}, // kbq -> Latn
+    {0xDC2A0000u, 40u}, // kbx -> Latn
+    {0xE02A0000u,  1u}, // kby -> Arab
+    {0x984A0000u, 40u}, // kcg -> Latn
+    {0xA84A0000u, 40u}, // kck -> Latn
+    {0xAC4A0000u, 40u}, // kcl -> Latn
+    {0xCC4A0000u, 40u}, // kct -> Latn
+    {0x906A0000u, 40u}, // kde -> Latn
+    {0x9C6A0000u,  1u}, // kdh -> Arab
+    {0xAC6A0000u, 40u}, // kdl -> Latn
+    {0xCC6A0000u, 80u}, // kdt -> Thai
+    {0x808A0000u, 40u}, // kea -> Latn
+    {0xB48A0000u, 40u}, // ken -> Latn
+    {0xE48A0000u, 40u}, // kez -> Latn
+    {0xB8AA0000u, 40u}, // kfo -> Latn
     {0xC4AA0000u, 16u}, // kfr -> Deva
     {0xE0AA0000u, 16u}, // kfy -> Deva
-    {0x6B670000u, 41u}, // kg -> Latn
-    {0x90CA0000u, 41u}, // kge -> Latn
-    {0xBCCA0000u, 41u}, // kgp -> Latn
-    {0x80EA0000u, 41u}, // kha -> Latn
+    {0x6B670000u, 40u}, // kg -> Latn
+    {0x90CA0000u, 40u}, // kge -> Latn
+    {0x94CA0000u, 40u}, // kgf -> Latn
+    {0xBCCA0000u, 40u}, // kgp -> Latn
+    {0x80EA0000u, 40u}, // kha -> Latn
     {0x84EA0000u, 73u}, // khb -> Talu
     {0xB4EA0000u, 16u}, // khn -> Deva
-    {0xC0EA0000u, 41u}, // khq -> Latn
-    {0xCCEA0000u, 53u}, // kht -> Mymr
+    {0xC0EA0000u, 40u}, // khq -> Latn
+    {0xC8EA0000u, 40u}, // khs -> Latn
+    {0xCCEA0000u, 52u}, // kht -> Mymr
     {0xD8EA0000u,  1u}, // khw -> Arab
-    {0x6B690000u, 41u}, // ki -> Latn
-    {0xD10A0000u, 41u}, // kiu -> Latn
-    {0x6B6A0000u, 41u}, // kj -> Latn
-    {0x992A0000u, 40u}, // kjg -> Laoo
+    {0xE4EA0000u, 40u}, // khz -> Latn
+    {0x6B690000u, 40u}, // ki -> Latn
+    {0xA50A0000u, 40u}, // kij -> Latn
+    {0xD10A0000u, 40u}, // kiu -> Latn
+    {0xD90A0000u, 40u}, // kiw -> Latn
+    {0x6B6A0000u, 40u}, // kj -> Latn
+    {0x8D2A0000u, 40u}, // kjd -> Latn
+    {0x992A0000u, 39u}, // kjg -> Laoo
+    {0xC92A0000u, 40u}, // kjs -> Latn
+    {0xE12A0000u, 40u}, // kjy -> Latn
     {0x6B6B0000u, 15u}, // kk -> Cyrl
     {0x6B6B4146u,  1u}, // kk-AF -> Arab
     {0x6B6B434Eu,  1u}, // kk-CN -> Arab
     {0x6B6B4952u,  1u}, // kk-IR -> Arab
     {0x6B6B4D4Eu,  1u}, // kk-MN -> Arab
-    {0xA54A0000u, 41u}, // kkj -> Latn
-    {0x6B6C0000u, 41u}, // kl -> Latn
-    {0xB56A0000u, 41u}, // kln -> Latn
+    {0x894A0000u, 40u}, // kkc -> Latn
+    {0xA54A0000u, 40u}, // kkj -> Latn
+    {0x6B6C0000u, 40u}, // kl -> Latn
+    {0xB56A0000u, 40u}, // kln -> Latn
+    {0xC16A0000u, 40u}, // klq -> Latn
+    {0xCD6A0000u, 40u}, // klt -> Latn
+    {0xDD6A0000u, 40u}, // klx -> Latn
     {0x6B6D0000u, 35u}, // km -> Khmr
-    {0x858A0000u, 41u}, // kmb -> Latn
+    {0x858A0000u, 40u}, // kmb -> Latn
+    {0x9D8A0000u, 40u}, // kmh -> Latn
+    {0xB98A0000u, 40u}, // kmo -> Latn
+    {0xC98A0000u, 40u}, // kms -> Latn
+    {0xD18A0000u, 40u}, // kmu -> Latn
+    {0xD98A0000u, 40u}, // kmw -> Latn
     {0x6B6E0000u, 36u}, // kn -> Knda
+    {0xBDAA0000u, 40u}, // knp -> Latn
     {0x6B6F0000u, 37u}, // ko -> Kore
     {0xA1CA0000u, 15u}, // koi -> Cyrl
     {0xA9CA0000u, 16u}, // kok -> Deva
-    {0xC9CA0000u, 41u}, // kos -> Latn
-    {0x91EA0000u, 41u}, // kpe -> Latn
+    {0xADCA0000u, 40u}, // kol -> Latn
+    {0xC9CA0000u, 40u}, // kos -> Latn
+    {0xE5CA0000u, 40u}, // koz -> Latn
+    {0x91EA0000u, 40u}, // kpe -> Latn
+    {0x95EA0000u, 40u}, // kpf -> Latn
+    {0xB9EA0000u, 40u}, // kpo -> Latn
+    {0xC5EA0000u, 40u}, // kpr -> Latn
+    {0xDDEA0000u, 40u}, // kpx -> Latn
+    {0x860A0000u, 40u}, // kqb -> Latn
+    {0x960A0000u, 40u}, // kqf -> Latn
+    {0xCA0A0000u, 40u}, // kqs -> Latn
+    {0xE20A0000u, 18u}, // kqy -> Ethi
     {0x8A2A0000u, 15u}, // krc -> Cyrl
-    {0xA22A0000u, 41u}, // kri -> Latn
-    {0xA62A0000u, 41u}, // krj -> Latn
-    {0xAE2A0000u, 41u}, // krl -> Latn
+    {0xA22A0000u, 40u}, // kri -> Latn
+    {0xA62A0000u, 40u}, // krj -> Latn
+    {0xAE2A0000u, 40u}, // krl -> Latn
+    {0xCA2A0000u, 40u}, // krs -> Latn
     {0xD22A0000u, 16u}, // kru -> Deva
     {0x6B730000u,  1u}, // ks -> Arab
-    {0x864A0000u, 41u}, // ksb -> Latn
-    {0x964A0000u, 41u}, // ksf -> Latn
-    {0x9E4A0000u, 41u}, // ksh -> Latn
-    {0x6B750000u, 41u}, // ku -> Latn
+    {0x864A0000u, 40u}, // ksb -> Latn
+    {0x8E4A0000u, 40u}, // ksd -> Latn
+    {0x964A0000u, 40u}, // ksf -> Latn
+    {0x9E4A0000u, 40u}, // ksh -> Latn
+    {0xA64A0000u, 40u}, // ksj -> Latn
+    {0xC64A0000u, 40u}, // ksr -> Latn
+    {0x866A0000u, 18u}, // ktb -> Ethi
+    {0xB26A0000u, 40u}, // ktm -> Latn
+    {0xBA6A0000u, 40u}, // kto -> Latn
+    {0x6B750000u, 40u}, // ku -> Latn
     {0x6B754952u,  1u}, // ku-IR -> Arab
     {0x6B754C42u,  1u}, // ku-LB -> Arab
+    {0x868A0000u, 40u}, // kub -> Latn
+    {0x8E8A0000u, 40u}, // kud -> Latn
+    {0x928A0000u, 40u}, // kue -> Latn
+    {0xA68A0000u, 40u}, // kuj -> Latn
     {0xB28A0000u, 15u}, // kum -> Cyrl
+    {0xB68A0000u, 40u}, // kun -> Latn
+    {0xBE8A0000u, 40u}, // kup -> Latn
+    {0xCA8A0000u, 40u}, // kus -> Latn
     {0x6B760000u, 15u}, // kv -> Cyrl
-    {0xC6AA0000u, 41u}, // kvr -> Latn
+    {0x9AAA0000u, 40u}, // kvg -> Latn
+    {0xC6AA0000u, 40u}, // kvr -> Latn
     {0xDEAA0000u,  1u}, // kvx -> Arab
-    {0x6B770000u, 41u}, // kw -> Latn
-    {0xB2EA0000u, 79u}, // kxm -> Thai
+    {0x6B770000u, 40u}, // kw -> Latn
+    {0xA6CA0000u, 40u}, // kwj -> Latn
+    {0xBACA0000u, 40u}, // kwo -> Latn
+    {0x82EA0000u, 40u}, // kxa -> Latn
+    {0x8AEA0000u, 18u}, // kxc -> Ethi
+    {0xB2EA0000u, 80u}, // kxm -> Thai
     {0xBEEA0000u,  1u}, // kxp -> Arab
+    {0xDAEA0000u, 40u}, // kxw -> Latn
+    {0xE6EA0000u, 40u}, // kxz -> Latn
     {0x6B790000u, 15u}, // ky -> Cyrl
     {0x6B79434Eu,  1u}, // ky-CN -> Arab
-    {0x6B795452u, 41u}, // ky-TR -> Latn
-    {0x6C610000u, 41u}, // la -> Latn
-    {0x840B0000u, 43u}, // lab -> Lina
+    {0x6B795452u, 40u}, // ky-TR -> Latn
+    {0x930A0000u, 40u}, // kye -> Latn
+    {0xDF0A0000u, 40u}, // kyx -> Latn
+    {0xC72A0000u, 40u}, // kzr -> Latn
+    {0x6C610000u, 40u}, // la -> Latn
+    {0x840B0000u, 42u}, // lab -> Lina
     {0x8C0B0000u, 27u}, // lad -> Hebr
-    {0x980B0000u, 41u}, // lag -> Latn
+    {0x980B0000u, 40u}, // lag -> Latn
     {0x9C0B0000u,  1u}, // lah -> Arab
-    {0xA40B0000u, 41u}, // laj -> Latn
-    {0x6C620000u, 41u}, // lb -> Latn
+    {0xA40B0000u, 40u}, // laj -> Latn
+    {0xC80B0000u, 40u}, // las -> Latn
+    {0x6C620000u, 40u}, // lb -> Latn
     {0x902B0000u, 15u}, // lbe -> Cyrl
-    {0xD82B0000u, 41u}, // lbw -> Latn
-    {0xBC4B0000u, 79u}, // lcp -> Thai
-    {0xBC8B0000u, 42u}, // lep -> Lepc
+    {0xD02B0000u, 40u}, // lbu -> Latn
+    {0xD82B0000u, 40u}, // lbw -> Latn
+    {0xB04B0000u, 40u}, // lcm -> Latn
+    {0xBC4B0000u, 80u}, // lcp -> Thai
+    {0x846B0000u, 40u}, // ldb -> Latn
+    {0x8C8B0000u, 40u}, // led -> Latn
+    {0x908B0000u, 40u}, // lee -> Latn
+    {0xB08B0000u, 40u}, // lem -> Latn
+    {0xBC8B0000u, 41u}, // lep -> Lepc
+    {0xC08B0000u, 40u}, // leq -> Latn
+    {0xD08B0000u, 40u}, // leu -> Latn
     {0xE48B0000u, 15u}, // lez -> Cyrl
-    {0x6C670000u, 41u}, // lg -> Latn
-    {0x6C690000u, 41u}, // li -> Latn
+    {0x6C670000u, 40u}, // lg -> Latn
+    {0x98CB0000u, 40u}, // lgg -> Latn
+    {0x6C690000u, 40u}, // li -> Latn
+    {0x810B0000u, 40u}, // lia -> Latn
+    {0x8D0B0000u, 40u}, // lid -> Latn
     {0x950B0000u, 16u}, // lif -> Deva
-    {0xA50B0000u, 41u}, // lij -> Latn
-    {0xC90B0000u, 44u}, // lis -> Lisu
-    {0xBD2B0000u, 41u}, // ljp -> Latn
+    {0x990B0000u, 40u}, // lig -> Latn
+    {0x9D0B0000u, 40u}, // lih -> Latn
+    {0xA50B0000u, 40u}, // lij -> Latn
+    {0xC90B0000u, 43u}, // lis -> Lisu
+    {0xBD2B0000u, 40u}, // ljp -> Latn
     {0xA14B0000u,  1u}, // lki -> Arab
-    {0xCD4B0000u, 41u}, // lkt -> Latn
-    {0xB58B0000u, 76u}, // lmn -> Telu
-    {0xB98B0000u, 41u}, // lmo -> Latn
-    {0x6C6E0000u, 41u}, // ln -> Latn
-    {0x6C6F0000u, 40u}, // lo -> Laoo
-    {0xADCB0000u, 41u}, // lol -> Latn
-    {0xE5CB0000u, 41u}, // loz -> Latn
+    {0xCD4B0000u, 40u}, // lkt -> Latn
+    {0x916B0000u, 40u}, // lle -> Latn
+    {0xB56B0000u, 40u}, // lln -> Latn
+    {0xB58B0000u, 77u}, // lmn -> Telu
+    {0xB98B0000u, 40u}, // lmo -> Latn
+    {0xBD8B0000u, 40u}, // lmp -> Latn
+    {0x6C6E0000u, 40u}, // ln -> Latn
+    {0xC9AB0000u, 40u}, // lns -> Latn
+    {0xD1AB0000u, 40u}, // lnu -> Latn
+    {0x6C6F0000u, 39u}, // lo -> Laoo
+    {0xA5CB0000u, 40u}, // loj -> Latn
+    {0xA9CB0000u, 40u}, // lok -> Latn
+    {0xADCB0000u, 40u}, // lol -> Latn
+    {0xC5CB0000u, 40u}, // lor -> Latn
+    {0xC9CB0000u, 40u}, // los -> Latn
+    {0xE5CB0000u, 40u}, // loz -> Latn
     {0x8A2B0000u,  1u}, // lrc -> Arab
-    {0x6C740000u, 41u}, // lt -> Latn
-    {0x9A6B0000u, 41u}, // ltg -> Latn
-    {0x6C750000u, 41u}, // lu -> Latn
-    {0x828B0000u, 41u}, // lua -> Latn
-    {0xBA8B0000u, 41u}, // luo -> Latn
-    {0xE28B0000u, 41u}, // luy -> Latn
+    {0x6C740000u, 40u}, // lt -> Latn
+    {0x9A6B0000u, 40u}, // ltg -> Latn
+    {0x6C750000u, 40u}, // lu -> Latn
+    {0x828B0000u, 40u}, // lua -> Latn
+    {0xBA8B0000u, 40u}, // luo -> Latn
+    {0xE28B0000u, 40u}, // luy -> Latn
     {0xE68B0000u,  1u}, // luz -> Arab
-    {0x6C760000u, 41u}, // lv -> Latn
-    {0xAECB0000u, 79u}, // lwl -> Thai
+    {0x6C760000u, 40u}, // lv -> Latn
+    {0xAECB0000u, 80u}, // lwl -> Thai
     {0x9F2B0000u, 24u}, // lzh -> Hans
-    {0xE72B0000u, 41u}, // lzz -> Latn
-    {0x8C0C0000u, 41u}, // mad -> Latn
-    {0x940C0000u, 41u}, // maf -> Latn
+    {0xE72B0000u, 40u}, // lzz -> Latn
+    {0x8C0C0000u, 40u}, // mad -> Latn
+    {0x940C0000u, 40u}, // maf -> Latn
     {0x980C0000u, 16u}, // mag -> Deva
     {0xA00C0000u, 16u}, // mai -> Deva
-    {0xA80C0000u, 41u}, // mak -> Latn
-    {0xB40C0000u, 41u}, // man -> Latn
-    {0xB40C474Eu, 55u}, // man-GN -> Nkoo
-    {0xC80C0000u, 41u}, // mas -> Latn
-    {0xE40C0000u, 41u}, // maz -> Latn
+    {0xA80C0000u, 40u}, // mak -> Latn
+    {0xB40C0000u, 40u}, // man -> Latn
+    {0xB40C474Eu, 54u}, // man-GN -> Nkoo
+    {0xC80C0000u, 40u}, // mas -> Latn
+    {0xD80C0000u, 40u}, // maw -> Latn
+    {0xE40C0000u, 40u}, // maz -> Latn
+    {0x9C2C0000u, 40u}, // mbh -> Latn
+    {0xB82C0000u, 40u}, // mbo -> Latn
+    {0xC02C0000u, 40u}, // mbq -> Latn
+    {0xD02C0000u, 40u}, // mbu -> Latn
+    {0xD82C0000u, 40u}, // mbw -> Latn
+    {0xA04C0000u, 40u}, // mci -> Latn
+    {0xBC4C0000u, 40u}, // mcp -> Latn
+    {0xC04C0000u, 40u}, // mcq -> Latn
+    {0xC44C0000u, 40u}, // mcr -> Latn
+    {0xD04C0000u, 40u}, // mcu -> Latn
+    {0x806C0000u, 40u}, // mda -> Latn
+    {0x906C0000u,  1u}, // mde -> Arab
     {0x946C0000u, 15u}, // mdf -> Cyrl
-    {0x9C6C0000u, 41u}, // mdh -> Latn
-    {0xC46C0000u, 41u}, // mdr -> Latn
-    {0xB48C0000u, 41u}, // men -> Latn
-    {0xC48C0000u, 41u}, // mer -> Latn
+    {0x9C6C0000u, 40u}, // mdh -> Latn
+    {0xA46C0000u, 40u}, // mdj -> Latn
+    {0xC46C0000u, 40u}, // mdr -> Latn
+    {0xDC6C0000u, 18u}, // mdx -> Ethi
+    {0x8C8C0000u, 40u}, // med -> Latn
+    {0x908C0000u, 40u}, // mee -> Latn
+    {0xA88C0000u, 40u}, // mek -> Latn
+    {0xB48C0000u, 40u}, // men -> Latn
+    {0xC48C0000u, 40u}, // mer -> Latn
+    {0xCC8C0000u, 40u}, // met -> Latn
+    {0xD08C0000u, 40u}, // meu -> Latn
     {0x80AC0000u,  1u}, // mfa -> Arab
-    {0x90AC0000u, 41u}, // mfe -> Latn
-    {0x6D670000u, 41u}, // mg -> Latn
-    {0x9CCC0000u, 41u}, // mgh -> Latn
-    {0xB8CC0000u, 41u}, // mgo -> Latn
+    {0x90AC0000u, 40u}, // mfe -> Latn
+    {0xB4AC0000u, 40u}, // mfn -> Latn
+    {0xB8AC0000u, 40u}, // mfo -> Latn
+    {0xC0AC0000u, 40u}, // mfq -> Latn
+    {0x6D670000u, 40u}, // mg -> Latn
+    {0x9CCC0000u, 40u}, // mgh -> Latn
+    {0xACCC0000u, 40u}, // mgl -> Latn
+    {0xB8CC0000u, 40u}, // mgo -> Latn
     {0xBCCC0000u, 16u}, // mgp -> Deva
-    {0xE0CC0000u, 41u}, // mgy -> Latn
-    {0x6D680000u, 41u}, // mh -> Latn
-    {0x6D690000u, 41u}, // mi -> Latn
-    {0xB50C0000u, 41u}, // min -> Latn
+    {0xE0CC0000u, 40u}, // mgy -> Latn
+    {0x6D680000u, 40u}, // mh -> Latn
+    {0xA0EC0000u, 40u}, // mhi -> Latn
+    {0xACEC0000u, 40u}, // mhl -> Latn
+    {0x6D690000u, 40u}, // mi -> Latn
+    {0x950C0000u, 40u}, // mif -> Latn
+    {0xB50C0000u, 40u}, // min -> Latn
     {0xC90C0000u, 26u}, // mis -> Hatr
+    {0xD90C0000u, 40u}, // miw -> Latn
     {0x6D6B0000u, 15u}, // mk -> Cyrl
-    {0x6D6C0000u, 50u}, // ml -> Mlym
-    {0xC96C0000u, 41u}, // mls -> Latn
+    {0xA14C0000u,  1u}, // mki -> Arab
+    {0xAD4C0000u, 40u}, // mkl -> Latn
+    {0xBD4C0000u, 40u}, // mkp -> Latn
+    {0xD94C0000u, 40u}, // mkw -> Latn
+    {0x6D6C0000u, 49u}, // ml -> Mlym
+    {0x916C0000u, 40u}, // mle -> Latn
+    {0xBD6C0000u, 40u}, // mlp -> Latn
+    {0xC96C0000u, 40u}, // mls -> Latn
+    {0xB98C0000u, 40u}, // mmo -> Latn
+    {0xD18C0000u, 40u}, // mmu -> Latn
+    {0xDD8C0000u, 40u}, // mmx -> Latn
     {0x6D6E0000u, 15u}, // mn -> Cyrl
-    {0x6D6E434Eu, 51u}, // mn-CN -> Mong
+    {0x6D6E434Eu, 50u}, // mn-CN -> Mong
+    {0x81AC0000u, 40u}, // mna -> Latn
+    {0x95AC0000u, 40u}, // mnf -> Latn
     {0xA1AC0000u,  7u}, // mni -> Beng
-    {0xD9AC0000u, 53u}, // mnw -> Mymr
-    {0x91CC0000u, 41u}, // moe -> Latn
-    {0x9DCC0000u, 41u}, // moh -> Latn
-    {0xC9CC0000u, 41u}, // mos -> Latn
+    {0xD9AC0000u, 52u}, // mnw -> Mymr
+    {0x81CC0000u, 40u}, // moa -> Latn
+    {0x91CC0000u, 40u}, // moe -> Latn
+    {0x9DCC0000u, 40u}, // moh -> Latn
+    {0xC9CC0000u, 40u}, // mos -> Latn
+    {0xDDCC0000u, 40u}, // mox -> Latn
+    {0xBDEC0000u, 40u}, // mpp -> Latn
+    {0xC9EC0000u, 40u}, // mps -> Latn
+    {0xCDEC0000u, 40u}, // mpt -> Latn
+    {0xDDEC0000u, 40u}, // mpx -> Latn
+    {0xAE0C0000u, 40u}, // mql -> Latn
     {0x6D720000u, 16u}, // mr -> Deva
     {0x8E2C0000u, 16u}, // mrd -> Deva
     {0xA62C0000u, 15u}, // mrj -> Cyrl
-    {0xD22C0000u, 52u}, // mru -> Mroo
-    {0x6D730000u, 41u}, // ms -> Latn
+    {0xBA2C0000u, 51u}, // mro -> Mroo
+    {0x6D730000u, 40u}, // ms -> Latn
     {0x6D734343u,  1u}, // ms-CC -> Arab
     {0x6D734944u,  1u}, // ms-ID -> Arab
-    {0x6D740000u, 41u}, // mt -> Latn
+    {0x6D740000u, 40u}, // mt -> Latn
+    {0x8A6C0000u, 40u}, // mtc -> Latn
+    {0x966C0000u, 40u}, // mtf -> Latn
+    {0xA26C0000u, 40u}, // mti -> Latn
     {0xC66C0000u, 16u}, // mtr -> Deva
-    {0x828C0000u, 41u}, // mua -> Latn
-    {0xCA8C0000u, 41u}, // mus -> Latn
+    {0x828C0000u, 40u}, // mua -> Latn
+    {0xC68C0000u, 40u}, // mur -> Latn
+    {0xCA8C0000u, 40u}, // mus -> Latn
+    {0x82AC0000u, 40u}, // mva -> Latn
+    {0xB6AC0000u, 40u}, // mvn -> Latn
     {0xE2AC0000u,  1u}, // mvy -> Arab
-    {0xAACC0000u, 41u}, // mwk -> Latn
+    {0xAACC0000u, 40u}, // mwk -> Latn
     {0xC6CC0000u, 16u}, // mwr -> Deva
-    {0xD6CC0000u, 41u}, // mwv -> Latn
-    {0x8AEC0000u, 41u}, // mxc -> Latn
-    {0x6D790000u, 53u}, // my -> Mymr
+    {0xD6CC0000u, 40u}, // mwv -> Latn
+    {0x8AEC0000u, 40u}, // mxc -> Latn
+    {0xB2EC0000u, 40u}, // mxm -> Latn
+    {0x6D790000u, 52u}, // my -> Mymr
+    {0xAB0C0000u, 40u}, // myk -> Latn
+    {0xB30C0000u, 18u}, // mym -> Ethi
     {0xD70C0000u, 15u}, // myv -> Cyrl
-    {0xDF0C0000u, 41u}, // myx -> Latn
-    {0xE70C0000u, 47u}, // myz -> Mand
+    {0xDB0C0000u, 40u}, // myw -> Latn
+    {0xDF0C0000u, 40u}, // myx -> Latn
+    {0xE70C0000u, 46u}, // myz -> Mand
+    {0xAB2C0000u, 40u}, // mzk -> Latn
+    {0xB32C0000u, 40u}, // mzm -> Latn
     {0xB72C0000u,  1u}, // mzn -> Arab
-    {0x6E610000u, 41u}, // na -> Latn
+    {0xBF2C0000u, 40u}, // mzp -> Latn
+    {0xDB2C0000u, 40u}, // mzw -> Latn
+    {0xE72C0000u, 40u}, // mzz -> Latn
+    {0x6E610000u, 40u}, // na -> Latn
+    {0x880D0000u, 40u}, // nac -> Latn
+    {0x940D0000u, 40u}, // naf -> Latn
+    {0xA80D0000u, 40u}, // nak -> Latn
     {0xB40D0000u, 24u}, // nan -> Hans
-    {0xBC0D0000u, 41u}, // nap -> Latn
-    {0xC00D0000u, 41u}, // naq -> Latn
-    {0x6E620000u, 41u}, // nb -> Latn
-    {0x9C4D0000u, 41u}, // nch -> Latn
-    {0x6E640000u, 41u}, // nd -> Latn
-    {0x886D0000u, 41u}, // ndc -> Latn
-    {0xC86D0000u, 41u}, // nds -> Latn
+    {0xBC0D0000u, 40u}, // nap -> Latn
+    {0xC00D0000u, 40u}, // naq -> Latn
+    {0xC80D0000u, 40u}, // nas -> Latn
+    {0x6E620000u, 40u}, // nb -> Latn
+    {0x804D0000u, 40u}, // nca -> Latn
+    {0x904D0000u, 40u}, // nce -> Latn
+    {0x944D0000u, 40u}, // ncf -> Latn
+    {0x9C4D0000u, 40u}, // nch -> Latn
+    {0xB84D0000u, 40u}, // nco -> Latn
+    {0xD04D0000u, 40u}, // ncu -> Latn
+    {0x6E640000u, 40u}, // nd -> Latn
+    {0x886D0000u, 40u}, // ndc -> Latn
+    {0xC86D0000u, 40u}, // nds -> Latn
     {0x6E650000u, 16u}, // ne -> Deva
+    {0x848D0000u, 40u}, // neb -> Latn
     {0xD88D0000u, 16u}, // new -> Deva
-    {0x6E670000u, 41u}, // ng -> Latn
-    {0xACCD0000u, 41u}, // ngl -> Latn
-    {0x90ED0000u, 41u}, // nhe -> Latn
-    {0xD8ED0000u, 41u}, // nhw -> Latn
-    {0xA50D0000u, 41u}, // nij -> Latn
-    {0xD10D0000u, 41u}, // niu -> Latn
-    {0xB92D0000u, 41u}, // njo -> Latn
-    {0x6E6C0000u, 41u}, // nl -> Latn
-    {0x998D0000u, 41u}, // nmg -> Latn
-    {0x6E6E0000u, 41u}, // nn -> Latn
-    {0x9DAD0000u, 41u}, // nnh -> Latn
-    {0x6E6F0000u, 41u}, // no -> Latn
-    {0x8DCD0000u, 39u}, // nod -> Lana
+    {0xDC8D0000u, 40u}, // nex -> Latn
+    {0xC4AD0000u, 40u}, // nfr -> Latn
+    {0x6E670000u, 40u}, // ng -> Latn
+    {0x80CD0000u, 40u}, // nga -> Latn
+    {0x84CD0000u, 40u}, // ngb -> Latn
+    {0xACCD0000u, 40u}, // ngl -> Latn
+    {0x84ED0000u, 40u}, // nhb -> Latn
+    {0x90ED0000u, 40u}, // nhe -> Latn
+    {0xD8ED0000u, 40u}, // nhw -> Latn
+    {0x950D0000u, 40u}, // nif -> Latn
+    {0xA10D0000u, 40u}, // nii -> Latn
+    {0xA50D0000u, 40u}, // nij -> Latn
+    {0xB50D0000u, 40u}, // nin -> Latn
+    {0xD10D0000u, 40u}, // niu -> Latn
+    {0xE10D0000u, 40u}, // niy -> Latn
+    {0xE50D0000u, 40u}, // niz -> Latn
+    {0xB92D0000u, 40u}, // njo -> Latn
+    {0x994D0000u, 40u}, // nkg -> Latn
+    {0xB94D0000u, 40u}, // nko -> Latn
+    {0x6E6C0000u, 40u}, // nl -> Latn
+    {0x998D0000u, 40u}, // nmg -> Latn
+    {0xE58D0000u, 40u}, // nmz -> Latn
+    {0x6E6E0000u, 40u}, // nn -> Latn
+    {0x95AD0000u, 40u}, // nnf -> Latn
+    {0x9DAD0000u, 40u}, // nnh -> Latn
+    {0xA9AD0000u, 40u}, // nnk -> Latn
+    {0xB1AD0000u, 40u}, // nnm -> Latn
+    {0x6E6F0000u, 40u}, // no -> Latn
+    {0x8DCD0000u, 38u}, // nod -> Lana
     {0x91CD0000u, 16u}, // noe -> Deva
     {0xB5CD0000u, 64u}, // non -> Runr
-    {0xBA0D0000u, 55u}, // nqo -> Nkoo
-    {0x6E720000u, 41u}, // nr -> Latn
+    {0xBDCD0000u, 40u}, // nop -> Latn
+    {0xD1CD0000u, 40u}, // nou -> Latn
+    {0xBA0D0000u, 54u}, // nqo -> Nkoo
+    {0x6E720000u, 40u}, // nr -> Latn
+    {0x862D0000u, 40u}, // nrb -> Latn
     {0xAA4D0000u,  9u}, // nsk -> Cans
-    {0xBA4D0000u, 41u}, // nso -> Latn
-    {0xCA8D0000u, 41u}, // nus -> Latn
-    {0x6E760000u, 41u}, // nv -> Latn
-    {0xC2ED0000u, 41u}, // nxq -> Latn
-    {0x6E790000u, 41u}, // ny -> Latn
-    {0xB30D0000u, 41u}, // nym -> Latn
-    {0xB70D0000u, 41u}, // nyn -> Latn
-    {0xA32D0000u, 41u}, // nzi -> Latn
-    {0x6F630000u, 41u}, // oc -> Latn
-    {0x6F6D0000u, 41u}, // om -> Latn
-    {0x6F720000u, 58u}, // or -> Orya
+    {0xB64D0000u, 40u}, // nsn -> Latn
+    {0xBA4D0000u, 40u}, // nso -> Latn
+    {0xCA4D0000u, 40u}, // nss -> Latn
+    {0xB26D0000u, 40u}, // ntm -> Latn
+    {0xC66D0000u, 40u}, // ntr -> Latn
+    {0xA28D0000u, 40u}, // nui -> Latn
+    {0xBE8D0000u, 40u}, // nup -> Latn
+    {0xCA8D0000u, 40u}, // nus -> Latn
+    {0xD68D0000u, 40u}, // nuv -> Latn
+    {0xDE8D0000u, 40u}, // nux -> Latn
+    {0x6E760000u, 40u}, // nv -> Latn
+    {0x86CD0000u, 40u}, // nwb -> Latn
+    {0xC2ED0000u, 40u}, // nxq -> Latn
+    {0xC6ED0000u, 40u}, // nxr -> Latn
+    {0x6E790000u, 40u}, // ny -> Latn
+    {0xB30D0000u, 40u}, // nym -> Latn
+    {0xB70D0000u, 40u}, // nyn -> Latn
+    {0xA32D0000u, 40u}, // nzi -> Latn
+    {0x6F630000u, 40u}, // oc -> Latn
+    {0x88CE0000u, 40u}, // ogc -> Latn
+    {0xC54E0000u, 40u}, // okr -> Latn
+    {0xD54E0000u, 40u}, // okv -> Latn
+    {0x6F6D0000u, 40u}, // om -> Latn
+    {0x99AE0000u, 40u}, // ong -> Latn
+    {0xB5AE0000u, 40u}, // onn -> Latn
+    {0xC9AE0000u, 40u}, // ons -> Latn
+    {0xB1EE0000u, 40u}, // opm -> Latn
+    {0x6F720000u, 57u}, // or -> Orya
+    {0xBA2E0000u, 40u}, // oro -> Latn
+    {0xD22E0000u,  1u}, // oru -> Arab
     {0x6F730000u, 15u}, // os -> Cyrl
-    {0xAA6E0000u, 57u}, // otk -> Orkh
+    {0x824E0000u, 58u}, // osa -> Osge
+    {0x826E0000u,  1u}, // ota -> Arab
+    {0xAA6E0000u, 56u}, // otk -> Orkh
+    {0xB32E0000u, 40u}, // ozm -> Latn
     {0x70610000u, 23u}, // pa -> Guru
     {0x7061504Bu,  1u}, // pa-PK -> Arab
-    {0x980F0000u, 41u}, // pag -> Latn
+    {0x980F0000u, 40u}, // pag -> Latn
     {0xAC0F0000u, 60u}, // pal -> Phli
-    {0xB00F0000u, 41u}, // pam -> Latn
-    {0xBC0F0000u, 41u}, // pap -> Latn
-    {0xD00F0000u, 41u}, // pau -> Latn
-    {0x8C4F0000u, 41u}, // pcd -> Latn
-    {0xB04F0000u, 41u}, // pcm -> Latn
-    {0x886F0000u, 41u}, // pdc -> Latn
-    {0xCC6F0000u, 41u}, // pdt -> Latn
-    {0xB88F0000u, 83u}, // peo -> Xpeo
-    {0xACAF0000u, 41u}, // pfl -> Latn
+    {0xB00F0000u, 40u}, // pam -> Latn
+    {0xBC0F0000u, 40u}, // pap -> Latn
+    {0xD00F0000u, 40u}, // pau -> Latn
+    {0xA02F0000u, 40u}, // pbi -> Latn
+    {0x8C4F0000u, 40u}, // pcd -> Latn
+    {0xB04F0000u, 40u}, // pcm -> Latn
+    {0x886F0000u, 40u}, // pdc -> Latn
+    {0xCC6F0000u, 40u}, // pdt -> Latn
+    {0x8C8F0000u, 40u}, // ped -> Latn
+    {0xB88F0000u, 84u}, // peo -> Xpeo
+    {0xDC8F0000u, 40u}, // pex -> Latn
+    {0xACAF0000u, 40u}, // pfl -> Latn
+    {0xACEF0000u,  1u}, // phl -> Arab
     {0xB4EF0000u, 61u}, // phn -> Phnx
+    {0xAD0F0000u, 40u}, // pil -> Latn
+    {0xBD0F0000u, 40u}, // pip -> Latn
     {0x814F0000u,  8u}, // pka -> Brah
-    {0xB94F0000u, 41u}, // pko -> Latn
-    {0x706C0000u, 41u}, // pl -> Latn
-    {0xC98F0000u, 41u}, // pms -> Latn
+    {0xB94F0000u, 40u}, // pko -> Latn
+    {0x706C0000u, 40u}, // pl -> Latn
+    {0x816F0000u, 40u}, // pla -> Latn
+    {0xC98F0000u, 40u}, // pms -> Latn
+    {0x99AF0000u, 40u}, // png -> Latn
+    {0xB5AF0000u, 40u}, // pnn -> Latn
     {0xCDAF0000u, 21u}, // pnt -> Grek
-    {0xB5CF0000u, 41u}, // pon -> Latn
+    {0xB5CF0000u, 40u}, // pon -> Latn
+    {0xB9EF0000u, 40u}, // ppo -> Latn
     {0x822F0000u, 34u}, // pra -> Khar
     {0x8E2F0000u,  1u}, // prd -> Arab
-    {0x9A2F0000u, 41u}, // prg -> Latn
+    {0x9A2F0000u, 40u}, // prg -> Latn
     {0x70730000u,  1u}, // ps -> Arab
-    {0x70740000u, 41u}, // pt -> Latn
-    {0xD28F0000u, 41u}, // puu -> Latn
-    {0x71750000u, 41u}, // qu -> Latn
-    {0x8A900000u, 41u}, // quc -> Latn
-    {0x9A900000u, 41u}, // qug -> Latn
+    {0xCA4F0000u, 40u}, // pss -> Latn
+    {0x70740000u, 40u}, // pt -> Latn
+    {0xBE6F0000u, 40u}, // ptp -> Latn
+    {0xD28F0000u, 40u}, // puu -> Latn
+    {0x82CF0000u, 40u}, // pwa -> Latn
+    {0x71750000u, 40u}, // qu -> Latn
+    {0x8A900000u, 40u}, // quc -> Latn
+    {0x9A900000u, 40u}, // qug -> Latn
+    {0xA0110000u, 40u}, // rai -> Latn
     {0xA4110000u, 16u}, // raj -> Deva
-    {0x94510000u, 41u}, // rcf -> Latn
-    {0xA4910000u, 41u}, // rej -> Latn
-    {0xB4D10000u, 41u}, // rgn -> Latn
-    {0x81110000u, 41u}, // ria -> Latn
-    {0x95110000u, 77u}, // rif -> Tfng
-    {0x95114E4Cu, 41u}, // rif-NL -> Latn
+    {0xB8110000u, 40u}, // rao -> Latn
+    {0x94510000u, 40u}, // rcf -> Latn
+    {0xA4910000u, 40u}, // rej -> Latn
+    {0xAC910000u, 40u}, // rel -> Latn
+    {0xC8910000u, 40u}, // res -> Latn
+    {0xB4D10000u, 40u}, // rgn -> Latn
+    {0x98F10000u,  1u}, // rhg -> Arab
+    {0x81110000u, 40u}, // ria -> Latn
+    {0x95110000u, 78u}, // rif -> Tfng
+    {0x95114E4Cu, 40u}, // rif-NL -> Latn
     {0xC9310000u, 16u}, // rjs -> Deva
     {0xCD510000u,  7u}, // rkt -> Beng
-    {0x726D0000u, 41u}, // rm -> Latn
-    {0x95910000u, 41u}, // rmf -> Latn
-    {0xB9910000u, 41u}, // rmo -> Latn
+    {0x726D0000u, 40u}, // rm -> Latn
+    {0x95910000u, 40u}, // rmf -> Latn
+    {0xB9910000u, 40u}, // rmo -> Latn
     {0xCD910000u,  1u}, // rmt -> Arab
-    {0xD1910000u, 41u}, // rmu -> Latn
-    {0x726E0000u, 41u}, // rn -> Latn
-    {0x99B10000u, 41u}, // rng -> Latn
-    {0x726F0000u, 41u}, // ro -> Latn
-    {0x85D10000u, 41u}, // rob -> Latn
-    {0x95D10000u, 41u}, // rof -> Latn
-    {0xB2710000u, 41u}, // rtm -> Latn
+    {0xD1910000u, 40u}, // rmu -> Latn
+    {0x726E0000u, 40u}, // rn -> Latn
+    {0x81B10000u, 40u}, // rna -> Latn
+    {0x99B10000u, 40u}, // rng -> Latn
+    {0x726F0000u, 40u}, // ro -> Latn
+    {0x85D10000u, 40u}, // rob -> Latn
+    {0x95D10000u, 40u}, // rof -> Latn
+    {0xB9D10000u, 40u}, // roo -> Latn
+    {0xBA310000u, 40u}, // rro -> Latn
+    {0xB2710000u, 40u}, // rtm -> Latn
     {0x72750000u, 15u}, // ru -> Cyrl
     {0x92910000u, 15u}, // rue -> Cyrl
-    {0x9A910000u, 41u}, // rug -> Latn
-    {0x72770000u, 41u}, // rw -> Latn
-    {0xAAD10000u, 41u}, // rwk -> Latn
+    {0x9A910000u, 40u}, // rug -> Latn
+    {0x72770000u, 40u}, // rw -> Latn
+    {0xAAD10000u, 40u}, // rwk -> Latn
+    {0xBAD10000u, 40u}, // rwo -> Latn
     {0xD3110000u, 33u}, // ryu -> Kana
     {0x73610000u, 16u}, // sa -> Deva
-    {0x94120000u, 41u}, // saf -> Latn
+    {0x94120000u, 40u}, // saf -> Latn
     {0x9C120000u, 15u}, // sah -> Cyrl
-    {0xC0120000u, 41u}, // saq -> Latn
-    {0xC8120000u, 41u}, // sas -> Latn
-    {0xCC120000u, 41u}, // sat -> Latn
+    {0xC0120000u, 40u}, // saq -> Latn
+    {0xC8120000u, 40u}, // sas -> Latn
+    {0xCC120000u, 40u}, // sat -> Latn
     {0xE4120000u, 67u}, // saz -> Saur
-    {0xBC320000u, 41u}, // sbp -> Latn
-    {0x73630000u, 41u}, // sc -> Latn
+    {0x80320000u, 40u}, // sba -> Latn
+    {0x90320000u, 40u}, // sbe -> Latn
+    {0xBC320000u, 40u}, // sbp -> Latn
+    {0x73630000u, 40u}, // sc -> Latn
     {0xA8520000u, 16u}, // sck -> Deva
-    {0xB4520000u, 41u}, // scn -> Latn
-    {0xB8520000u, 41u}, // sco -> Latn
-    {0xC8520000u, 41u}, // scs -> Latn
+    {0xAC520000u,  1u}, // scl -> Arab
+    {0xB4520000u, 40u}, // scn -> Latn
+    {0xB8520000u, 40u}, // sco -> Latn
+    {0xC8520000u, 40u}, // scs -> Latn
     {0x73640000u,  1u}, // sd -> Arab
-    {0x88720000u, 41u}, // sdc -> Latn
+    {0x88720000u, 40u}, // sdc -> Latn
     {0x9C720000u,  1u}, // sdh -> Arab
-    {0x73650000u, 41u}, // se -> Latn
-    {0x94920000u, 41u}, // sef -> Latn
-    {0x9C920000u, 41u}, // seh -> Latn
-    {0xA0920000u, 41u}, // sei -> Latn
-    {0xC8920000u, 41u}, // ses -> Latn
-    {0x73670000u, 41u}, // sg -> Latn
-    {0x80D20000u, 56u}, // sga -> Ogam
-    {0xC8D20000u, 41u}, // sgs -> Latn
-    {0x73680000u, 41u}, // sh -> Latn
-    {0xA0F20000u, 77u}, // shi -> Tfng
-    {0xB4F20000u, 53u}, // shn -> Mymr
+    {0x73650000u, 40u}, // se -> Latn
+    {0x94920000u, 40u}, // sef -> Latn
+    {0x9C920000u, 40u}, // seh -> Latn
+    {0xA0920000u, 40u}, // sei -> Latn
+    {0xC8920000u, 40u}, // ses -> Latn
+    {0x73670000u, 40u}, // sg -> Latn
+    {0x80D20000u, 55u}, // sga -> Ogam
+    {0xC8D20000u, 40u}, // sgs -> Latn
+    {0xD8D20000u, 18u}, // sgw -> Ethi
+    {0xE4D20000u, 40u}, // sgz -> Latn
+    {0x73680000u, 40u}, // sh -> Latn
+    {0xA0F20000u, 78u}, // shi -> Tfng
+    {0xA8F20000u, 40u}, // shk -> Latn
+    {0xB4F20000u, 52u}, // shn -> Mymr
+    {0xD0F20000u,  1u}, // shu -> Arab
     {0x73690000u, 69u}, // si -> Sinh
-    {0x8D120000u, 41u}, // sid -> Latn
-    {0x736B0000u, 41u}, // sk -> Latn
+    {0x8D120000u, 40u}, // sid -> Latn
+    {0x99120000u, 40u}, // sig -> Latn
+    {0xAD120000u, 40u}, // sil -> Latn
+    {0xB1120000u, 40u}, // sim -> Latn
+    {0xC5320000u, 40u}, // sjr -> Latn
+    {0x736B0000u, 40u}, // sk -> Latn
+    {0x89520000u, 40u}, // skc -> Latn
     {0xC5520000u,  1u}, // skr -> Arab
-    {0x736C0000u, 41u}, // sl -> Latn
-    {0xA1720000u, 41u}, // sli -> Latn
-    {0xE1720000u, 41u}, // sly -> Latn
-    {0x736D0000u, 41u}, // sm -> Latn
-    {0x81920000u, 41u}, // sma -> Latn
-    {0xA5920000u, 41u}, // smj -> Latn
-    {0xB5920000u, 41u}, // smn -> Latn
+    {0xC9520000u, 40u}, // sks -> Latn
+    {0x736C0000u, 40u}, // sl -> Latn
+    {0x8D720000u, 40u}, // sld -> Latn
+    {0xA1720000u, 40u}, // sli -> Latn
+    {0xAD720000u, 40u}, // sll -> Latn
+    {0xE1720000u, 40u}, // sly -> Latn
+    {0x736D0000u, 40u}, // sm -> Latn
+    {0x81920000u, 40u}, // sma -> Latn
+    {0xA5920000u, 40u}, // smj -> Latn
+    {0xB5920000u, 40u}, // smn -> Latn
     {0xBD920000u, 65u}, // smp -> Samr
-    {0xC9920000u, 41u}, // sms -> Latn
-    {0x736E0000u, 41u}, // sn -> Latn
-    {0xA9B20000u, 41u}, // snk -> Latn
-    {0x736F0000u, 41u}, // so -> Latn
-    {0xD1D20000u, 79u}, // sou -> Thai
-    {0x73710000u, 41u}, // sq -> Latn
+    {0xC1920000u, 40u}, // smq -> Latn
+    {0xC9920000u, 40u}, // sms -> Latn
+    {0x736E0000u, 40u}, // sn -> Latn
+    {0x89B20000u, 40u}, // snc -> Latn
+    {0xA9B20000u, 40u}, // snk -> Latn
+    {0xBDB20000u, 40u}, // snp -> Latn
+    {0xDDB20000u, 40u}, // snx -> Latn
+    {0xE1B20000u, 40u}, // sny -> Latn
+    {0x736F0000u, 40u}, // so -> Latn
+    {0xA9D20000u, 40u}, // sok -> Latn
+    {0xC1D20000u, 40u}, // soq -> Latn
+    {0xD1D20000u, 80u}, // sou -> Thai
+    {0xE1D20000u, 40u}, // soy -> Latn
+    {0x8DF20000u, 40u}, // spd -> Latn
+    {0xADF20000u, 40u}, // spl -> Latn
+    {0xC9F20000u, 40u}, // sps -> Latn
+    {0x73710000u, 40u}, // sq -> Latn
     {0x73720000u, 15u}, // sr -> Cyrl
-    {0x73724D45u, 41u}, // sr-ME -> Latn
-    {0x7372524Fu, 41u}, // sr-RO -> Latn
-    {0x73725255u, 41u}, // sr-RU -> Latn
-    {0x73725452u, 41u}, // sr-TR -> Latn
+    {0x73724D45u, 40u}, // sr-ME -> Latn
+    {0x7372524Fu, 40u}, // sr-RO -> Latn
+    {0x73725255u, 40u}, // sr-RU -> Latn
+    {0x73725452u, 40u}, // sr-TR -> Latn
     {0x86320000u, 70u}, // srb -> Sora
-    {0xB6320000u, 41u}, // srn -> Latn
-    {0xC6320000u, 41u}, // srr -> Latn
+    {0xB6320000u, 40u}, // srn -> Latn
+    {0xC6320000u, 40u}, // srr -> Latn
     {0xDE320000u, 16u}, // srx -> Deva
-    {0x73730000u, 41u}, // ss -> Latn
-    {0xE2520000u, 41u}, // ssy -> Latn
-    {0x73740000u, 41u}, // st -> Latn
-    {0xC2720000u, 41u}, // stq -> Latn
-    {0x73750000u, 41u}, // su -> Latn
-    {0xAA920000u, 41u}, // suk -> Latn
-    {0xCA920000u, 41u}, // sus -> Latn
-    {0x73760000u, 41u}, // sv -> Latn
-    {0x73770000u, 41u}, // sw -> Latn
+    {0x73730000u, 40u}, // ss -> Latn
+    {0x8E520000u, 40u}, // ssd -> Latn
+    {0x9A520000u, 40u}, // ssg -> Latn
+    {0xE2520000u, 40u}, // ssy -> Latn
+    {0x73740000u, 40u}, // st -> Latn
+    {0xAA720000u, 40u}, // stk -> Latn
+    {0xC2720000u, 40u}, // stq -> Latn
+    {0x73750000u, 40u}, // su -> Latn
+    {0x82920000u, 40u}, // sua -> Latn
+    {0x92920000u, 40u}, // sue -> Latn
+    {0xAA920000u, 40u}, // suk -> Latn
+    {0xC6920000u, 40u}, // sur -> Latn
+    {0xCA920000u, 40u}, // sus -> Latn
+    {0x73760000u, 40u}, // sv -> Latn
+    {0x73770000u, 40u}, // sw -> Latn
     {0x86D20000u,  1u}, // swb -> Arab
-    {0x8AD20000u, 41u}, // swc -> Latn
-    {0x9AD20000u, 41u}, // swg -> Latn
+    {0x8AD20000u, 40u}, // swc -> Latn
+    {0x9AD20000u, 40u}, // swg -> Latn
+    {0xBED20000u, 40u}, // swp -> Latn
     {0xD6D20000u, 16u}, // swv -> Deva
-    {0xB6F20000u, 41u}, // sxn -> Latn
+    {0xB6F20000u, 40u}, // sxn -> Latn
+    {0xDAF20000u, 40u}, // sxw -> Latn
     {0xAF120000u,  7u}, // syl -> Beng
     {0xC7120000u, 71u}, // syr -> Syrc
-    {0xAF320000u, 41u}, // szl -> Latn
+    {0xAF320000u, 40u}, // szl -> Latn
     {0x74610000u, 74u}, // ta -> Taml
     {0xA4130000u, 16u}, // taj -> Deva
-    {0xD8330000u, 41u}, // tbw -> Latn
+    {0xAC130000u, 40u}, // tal -> Latn
+    {0xB4130000u, 40u}, // tan -> Latn
+    {0xC0130000u, 40u}, // taq -> Latn
+    {0x88330000u, 40u}, // tbc -> Latn
+    {0x8C330000u, 40u}, // tbd -> Latn
+    {0x94330000u, 40u}, // tbf -> Latn
+    {0x98330000u, 40u}, // tbg -> Latn
+    {0xB8330000u, 40u}, // tbo -> Latn
+    {0xD8330000u, 40u}, // tbw -> Latn
+    {0xE4330000u, 40u}, // tbz -> Latn
+    {0xA0530000u, 40u}, // tci -> Latn
     {0xE0530000u, 36u}, // tcy -> Knda
     {0x8C730000u, 72u}, // tdd -> Tale
     {0x98730000u, 16u}, // tdg -> Deva
     {0x9C730000u, 16u}, // tdh -> Deva
-    {0x74650000u, 76u}, // te -> Telu
-    {0xB0930000u, 41u}, // tem -> Latn
-    {0xB8930000u, 41u}, // teo -> Latn
-    {0xCC930000u, 41u}, // tet -> Latn
+    {0x74650000u, 77u}, // te -> Telu
+    {0x8C930000u, 40u}, // ted -> Latn
+    {0xB0930000u, 40u}, // tem -> Latn
+    {0xB8930000u, 40u}, // teo -> Latn
+    {0xCC930000u, 40u}, // tet -> Latn
+    {0xA0B30000u, 40u}, // tfi -> Latn
     {0x74670000u, 15u}, // tg -> Cyrl
     {0x7467504Bu,  1u}, // tg-PK -> Arab
-    {0x74680000u, 79u}, // th -> Thai
+    {0x88D30000u, 40u}, // tgc -> Latn
+    {0xB8D30000u, 40u}, // tgo -> Latn
+    {0xD0D30000u, 40u}, // tgu -> Latn
+    {0x74680000u, 80u}, // th -> Thai
     {0xACF30000u, 16u}, // thl -> Deva
     {0xC0F30000u, 16u}, // thq -> Deva
     {0xC4F30000u, 16u}, // thr -> Deva
     {0x74690000u, 18u}, // ti -> Ethi
+    {0x95130000u, 40u}, // tif -> Latn
     {0x99130000u, 18u}, // tig -> Ethi
-    {0xD5130000u, 41u}, // tiv -> Latn
-    {0x746B0000u, 41u}, // tk -> Latn
-    {0xAD530000u, 41u}, // tkl -> Latn
-    {0xC5530000u, 41u}, // tkr -> Latn
+    {0xA9130000u, 40u}, // tik -> Latn
+    {0xB1130000u, 40u}, // tim -> Latn
+    {0xB9130000u, 40u}, // tio -> Latn
+    {0xD5130000u, 40u}, // tiv -> Latn
+    {0x746B0000u, 40u}, // tk -> Latn
+    {0xAD530000u, 40u}, // tkl -> Latn
+    {0xC5530000u, 40u}, // tkr -> Latn
     {0xCD530000u, 16u}, // tkt -> Deva
-    {0x746C0000u, 41u}, // tl -> Latn
-    {0xE1730000u, 41u}, // tly -> Latn
-    {0x9D930000u, 41u}, // tmh -> Latn
-    {0x746E0000u, 41u}, // tn -> Latn
-    {0x746F0000u, 41u}, // to -> Latn
-    {0x99D30000u, 41u}, // tog -> Latn
-    {0xA1F30000u, 41u}, // tpi -> Latn
-    {0x74720000u, 41u}, // tr -> Latn
-    {0xD2330000u, 41u}, // tru -> Latn
-    {0xD6330000u, 41u}, // trv -> Latn
-    {0x74730000u, 41u}, // ts -> Latn
+    {0x746C0000u, 40u}, // tl -> Latn
+    {0x95730000u, 40u}, // tlf -> Latn
+    {0xDD730000u, 40u}, // tlx -> Latn
+    {0xE1730000u, 40u}, // tly -> Latn
+    {0x9D930000u, 40u}, // tmh -> Latn
+    {0xE1930000u, 40u}, // tmy -> Latn
+    {0x746E0000u, 40u}, // tn -> Latn
+    {0x9DB30000u, 40u}, // tnh -> Latn
+    {0x746F0000u, 40u}, // to -> Latn
+    {0x95D30000u, 40u}, // tof -> Latn
+    {0x99D30000u, 40u}, // tog -> Latn
+    {0xC1D30000u, 40u}, // toq -> Latn
+    {0xA1F30000u, 40u}, // tpi -> Latn
+    {0xB1F30000u, 40u}, // tpm -> Latn
+    {0xE5F30000u, 40u}, // tpz -> Latn
+    {0xBA130000u, 40u}, // tqo -> Latn
+    {0x74720000u, 40u}, // tr -> Latn
+    {0xD2330000u, 40u}, // tru -> Latn
+    {0xD6330000u, 40u}, // trv -> Latn
+    {0xDA330000u,  1u}, // trw -> Arab
+    {0x74730000u, 40u}, // ts -> Latn
     {0x8E530000u, 21u}, // tsd -> Grek
     {0x96530000u, 16u}, // tsf -> Deva
-    {0x9A530000u, 41u}, // tsg -> Latn
-    {0xA6530000u, 80u}, // tsj -> Tibt
+    {0x9A530000u, 40u}, // tsg -> Latn
+    {0xA6530000u, 81u}, // tsj -> Tibt
+    {0xDA530000u, 40u}, // tsw -> Latn
     {0x74740000u, 15u}, // tt -> Cyrl
-    {0xA6730000u, 41u}, // ttj -> Latn
-    {0xCA730000u, 79u}, // tts -> Thai
-    {0xCE730000u, 41u}, // ttt -> Latn
-    {0xB2930000u, 41u}, // tum -> Latn
-    {0xAEB30000u, 41u}, // tvl -> Latn
-    {0xC2D30000u, 41u}, // twq -> Latn
-    {0x74790000u, 41u}, // ty -> Latn
+    {0x8E730000u, 40u}, // ttd -> Latn
+    {0x92730000u, 40u}, // tte -> Latn
+    {0xA6730000u, 40u}, // ttj -> Latn
+    {0xC6730000u, 40u}, // ttr -> Latn
+    {0xCA730000u, 80u}, // tts -> Thai
+    {0xCE730000u, 40u}, // ttt -> Latn
+    {0x9E930000u, 40u}, // tuh -> Latn
+    {0xAE930000u, 40u}, // tul -> Latn
+    {0xB2930000u, 40u}, // tum -> Latn
+    {0xC2930000u, 40u}, // tuq -> Latn
+    {0x8EB30000u, 40u}, // tvd -> Latn
+    {0xAEB30000u, 40u}, // tvl -> Latn
+    {0xD2B30000u, 40u}, // tvu -> Latn
+    {0x9ED30000u, 40u}, // twh -> Latn
+    {0xC2D30000u, 40u}, // twq -> Latn
+    {0x9AF30000u, 75u}, // txg -> Tang
+    {0x74790000u, 40u}, // ty -> Latn
+    {0x83130000u, 40u}, // tya -> Latn
     {0xD7130000u, 15u}, // tyv -> Cyrl
-    {0xB3330000u, 41u}, // tzm -> Latn
+    {0xB3330000u, 40u}, // tzm -> Latn
+    {0xD0340000u, 40u}, // ubu -> Latn
     {0xB0740000u, 15u}, // udm -> Cyrl
     {0x75670000u,  1u}, // ug -> Arab
     {0x75674B5Au, 15u}, // ug-KZ -> Cyrl
     {0x75674D4Eu, 15u}, // ug-MN -> Cyrl
-    {0x80D40000u, 81u}, // uga -> Ugar
+    {0x80D40000u, 82u}, // uga -> Ugar
     {0x756B0000u, 15u}, // uk -> Cyrl
-    {0xA1740000u, 41u}, // uli -> Latn
-    {0x85940000u, 41u}, // umb -> Latn
+    {0xA1740000u, 40u}, // uli -> Latn
+    {0x85940000u, 40u}, // umb -> Latn
     {0xC5B40000u,  7u}, // unr -> Beng
     {0xC5B44E50u, 16u}, // unr-NP -> Deva
     {0xDDB40000u,  7u}, // unx -> Beng
     {0x75720000u,  1u}, // ur -> Arab
-    {0x757A0000u, 41u}, // uz -> Latn
+    {0xA2340000u, 40u}, // uri -> Latn
+    {0xCE340000u, 40u}, // urt -> Latn
+    {0xDA340000u, 40u}, // urw -> Latn
+    {0x82540000u, 40u}, // usa -> Latn
+    {0xC6740000u, 40u}, // utr -> Latn
+    {0x9EB40000u, 40u}, // uvh -> Latn
+    {0xAEB40000u, 40u}, // uvl -> Latn
+    {0x757A0000u, 40u}, // uz -> Latn
     {0x757A4146u,  1u}, // uz-AF -> Arab
     {0x757A434Eu, 15u}, // uz-CN -> Cyrl
-    {0xA0150000u, 82u}, // vai -> Vaii
-    {0x76650000u, 41u}, // ve -> Latn
-    {0x88950000u, 41u}, // vec -> Latn
-    {0xBC950000u, 41u}, // vep -> Latn
-    {0x76690000u, 41u}, // vi -> Latn
-    {0x89150000u, 41u}, // vic -> Latn
-    {0xC9750000u, 41u}, // vls -> Latn
-    {0x95950000u, 41u}, // vmf -> Latn
-    {0xD9950000u, 41u}, // vmw -> Latn
-    {0x766F0000u, 41u}, // vo -> Latn
-    {0xCDD50000u, 41u}, // vot -> Latn
-    {0xBA350000u, 41u}, // vro -> Latn
-    {0xB6950000u, 41u}, // vun -> Latn
-    {0x77610000u, 41u}, // wa -> Latn
-    {0x90160000u, 41u}, // wae -> Latn
+    {0x98150000u, 40u}, // vag -> Latn
+    {0xA0150000u, 83u}, // vai -> Vaii
+    {0xB4150000u, 40u}, // van -> Latn
+    {0x76650000u, 40u}, // ve -> Latn
+    {0x88950000u, 40u}, // vec -> Latn
+    {0xBC950000u, 40u}, // vep -> Latn
+    {0x76690000u, 40u}, // vi -> Latn
+    {0x89150000u, 40u}, // vic -> Latn
+    {0xD5150000u, 40u}, // viv -> Latn
+    {0xC9750000u, 40u}, // vls -> Latn
+    {0x95950000u, 40u}, // vmf -> Latn
+    {0xD9950000u, 40u}, // vmw -> Latn
+    {0x766F0000u, 40u}, // vo -> Latn
+    {0xCDD50000u, 40u}, // vot -> Latn
+    {0xBA350000u, 40u}, // vro -> Latn
+    {0xB6950000u, 40u}, // vun -> Latn
+    {0xCE950000u, 40u}, // vut -> Latn
+    {0x77610000u, 40u}, // wa -> Latn
+    {0x90160000u, 40u}, // wae -> Latn
+    {0xA4160000u, 40u}, // waj -> Latn
     {0xAC160000u, 18u}, // wal -> Ethi
-    {0xC4160000u, 41u}, // war -> Latn
-    {0xBC360000u, 41u}, // wbp -> Latn
-    {0xC0360000u, 76u}, // wbq -> Telu
+    {0xB4160000u, 40u}, // wan -> Latn
+    {0xC4160000u, 40u}, // war -> Latn
+    {0xBC360000u, 40u}, // wbp -> Latn
+    {0xC0360000u, 77u}, // wbq -> Telu
     {0xC4360000u, 16u}, // wbr -> Deva
-    {0xC9760000u, 41u}, // wls -> Latn
+    {0xA0560000u, 40u}, // wci -> Latn
+    {0xC4960000u, 40u}, // wer -> Latn
+    {0xA0D60000u, 40u}, // wgi -> Latn
+    {0x98F60000u, 40u}, // whg -> Latn
+    {0x85160000u, 40u}, // wib -> Latn
+    {0xD1160000u, 40u}, // wiu -> Latn
+    {0xD5160000u, 40u}, // wiv -> Latn
+    {0x81360000u, 40u}, // wja -> Latn
+    {0xA1360000u, 40u}, // wji -> Latn
+    {0xC9760000u, 40u}, // wls -> Latn
+    {0xB9960000u, 40u}, // wmo -> Latn
+    {0x89B60000u, 40u}, // wnc -> Latn
     {0xA1B60000u,  1u}, // wni -> Arab
-    {0x776F0000u, 41u}, // wo -> Latn
+    {0xD1B60000u, 40u}, // wnu -> Latn
+    {0x776F0000u, 40u}, // wo -> Latn
+    {0x85D60000u, 40u}, // wob -> Latn
+    {0xC9D60000u, 40u}, // wos -> Latn
+    {0xCA360000u, 40u}, // wrs -> Latn
+    {0xAA560000u, 40u}, // wsk -> Latn
     {0xB2760000u, 16u}, // wtm -> Deva
     {0xD2960000u, 24u}, // wuu -> Hans
-    {0xD4170000u, 41u}, // xav -> Latn
+    {0xD6960000u, 40u}, // wuv -> Latn
+    {0x82D60000u, 40u}, // wwa -> Latn
+    {0xD4170000u, 40u}, // xav -> Latn
+    {0xA0370000u, 40u}, // xbi -> Latn
     {0xC4570000u, 10u}, // xcr -> Cari
-    {0x78680000u, 41u}, // xh -> Latn
-    {0x89770000u, 45u}, // xlc -> Lyci
-    {0x8D770000u, 46u}, // xld -> Lydi
+    {0xC8970000u, 40u}, // xes -> Latn
+    {0x78680000u, 40u}, // xh -> Latn
+    {0x81770000u, 40u}, // xla -> Latn
+    {0x89770000u, 44u}, // xlc -> Lyci
+    {0x8D770000u, 45u}, // xld -> Lydi
     {0x95970000u, 19u}, // xmf -> Geor
-    {0xB5970000u, 48u}, // xmn -> Mani
-    {0xC5970000u, 49u}, // xmr -> Merc
-    {0x81B70000u, 54u}, // xna -> Narb
+    {0xB5970000u, 47u}, // xmn -> Mani
+    {0xC5970000u, 48u}, // xmr -> Merc
+    {0x81B70000u, 53u}, // xna -> Narb
     {0xC5B70000u, 16u}, // xnr -> Deva
-    {0x99D70000u, 41u}, // xog -> Latn
+    {0x99D70000u, 40u}, // xog -> Latn
+    {0xB5D70000u, 40u}, // xon -> Latn
     {0xC5F70000u, 63u}, // xpr -> Prti
+    {0x86370000u, 40u}, // xrb -> Latn
     {0x82570000u, 66u}, // xsa -> Sarb
+    {0xA2570000u, 40u}, // xsi -> Latn
+    {0xB2570000u, 40u}, // xsm -> Latn
     {0xC6570000u, 16u}, // xsr -> Deva
-    {0xB8180000u, 41u}, // yao -> Latn
-    {0xBC180000u, 41u}, // yap -> Latn
-    {0xD4180000u, 41u}, // yav -> Latn
-    {0x84380000u, 41u}, // ybb -> Latn
+    {0x92D70000u, 40u}, // xwe -> Latn
+    {0xB0180000u, 40u}, // yam -> Latn
+    {0xB8180000u, 40u}, // yao -> Latn
+    {0xBC180000u, 40u}, // yap -> Latn
+    {0xC8180000u, 40u}, // yas -> Latn
+    {0xCC180000u, 40u}, // yat -> Latn
+    {0xD4180000u, 40u}, // yav -> Latn
+    {0xE0180000u, 40u}, // yay -> Latn
+    {0xE4180000u, 40u}, // yaz -> Latn
+    {0x80380000u, 40u}, // yba -> Latn
+    {0x84380000u, 40u}, // ybb -> Latn
+    {0xE0380000u, 40u}, // yby -> Latn
+    {0xC4980000u, 40u}, // yer -> Latn
+    {0xC4D80000u, 40u}, // ygr -> Latn
+    {0xD8D80000u, 40u}, // ygw -> Latn
     {0x79690000u, 27u}, // yi -> Hebr
-    {0x796F0000u, 41u}, // yo -> Latn
-    {0xAE380000u, 41u}, // yrl -> Latn
-    {0x82980000u, 41u}, // yua -> Latn
-    {0x7A610000u, 41u}, // za -> Latn
-    {0x98190000u, 41u}, // zag -> Latn
+    {0xB9580000u, 40u}, // yko -> Latn
+    {0x91780000u, 40u}, // yle -> Latn
+    {0x99780000u, 40u}, // ylg -> Latn
+    {0xAD780000u, 40u}, // yll -> Latn
+    {0xAD980000u, 40u}, // yml -> Latn
+    {0x796F0000u, 40u}, // yo -> Latn
+    {0xB5D80000u, 40u}, // yon -> Latn
+    {0x86380000u, 40u}, // yrb -> Latn
+    {0x92380000u, 40u}, // yre -> Latn
+    {0xAE380000u, 40u}, // yrl -> Latn
+    {0xCA580000u, 40u}, // yss -> Latn
+    {0x82980000u, 40u}, // yua -> Latn
+    {0x92980000u, 25u}, // yue -> Hant
+    {0x9298434Eu, 24u}, // yue-CN -> Hans
+    {0xA6980000u, 40u}, // yuj -> Latn
+    {0xCE980000u, 40u}, // yut -> Latn
+    {0xDA980000u, 40u}, // yuw -> Latn
+    {0x7A610000u, 40u}, // za -> Latn
+    {0x98190000u, 40u}, // zag -> Latn
     {0xA4790000u,  1u}, // zdj -> Arab
-    {0x80990000u, 41u}, // zea -> Latn
-    {0x9CD90000u, 77u}, // zgh -> Tfng
+    {0x80990000u, 40u}, // zea -> Latn
+    {0x9CD90000u, 78u}, // zgh -> Tfng
     {0x7A680000u, 24u}, // zh -> Hans
     {0x7A684155u, 25u}, // zh-AU -> Hant
     {0x7A68424Eu, 25u}, // zh-BN -> Hant
@@ -829,9 +1437,12 @@
     {0x7A685457u, 25u}, // zh-TW -> Hant
     {0x7A685553u, 25u}, // zh-US -> Hant
     {0x7A68564Eu, 25u}, // zh-VN -> Hant
-    {0xA1990000u, 41u}, // zmi -> Latn
-    {0x7A750000u, 41u}, // zu -> Latn
-    {0x83390000u, 41u}, // zza -> Latn
+    {0x81190000u, 40u}, // zia -> Latn
+    {0xB1790000u, 40u}, // zlm -> Latn
+    {0xA1990000u, 40u}, // zmi -> Latn
+    {0x91B90000u, 40u}, // zne -> Latn
+    {0x7A750000u, 40u}, // zu -> Latn
+    {0x83390000u, 40u}, // zza -> Latn
 });
 
 std::unordered_set<uint64_t> REPRESENTATIVE_LOCALES({
@@ -854,6 +1465,7 @@
     0x616D455445746869llu, // am_Ethi_ET
     0xB9804E474C61746Ellu, // amo_Latn_NG
     0xE5C049444C61746Ellu, // aoz_Latn_ID
+    0x8DE0544741726162llu, // apd_Arab_TG
     0x6172454741726162llu, // ar_Arab_EG
     0x8A20495241726D69llu, // arc_Armi_IR
     0x8A204A4F4E626174llu, // arc_Nbat_JO
@@ -896,7 +1508,6 @@
     0x88C1494E44657661llu, // bgc_Deva_IN
     0xB4C1504B41726162llu, // bgn_Arab_PK
     0xDCC154524772656Bllu, // bgx_Grek_TR
-    0x6268494E4B746869llu, // bh_Kthi_IN
     0x84E1494E44657661llu, // bhb_Deva_IN
     0xA0E1494E44657661llu, // bhi_Deva_IN
     0xA8E150484C61746Ellu, // bhk_Latn_PH
@@ -980,6 +1591,7 @@
     0x864344454C61746Ellu, // dsb_Latn_DE
     0xB2634D4C4C61746Ellu, // dtm_Latn_ML
     0xBE634D594C61746Ellu, // dtp_Latn_MY
+    0xE2634E5044657661llu, // dty_Deva_NP
     0x8283434D4C61746Ellu, // dua_Latn_CM
     0x64764D5654686161llu, // dv_Thaa_MV
     0xBB03534E4C61746Ellu, // dyo_Latn_SN
@@ -1006,6 +1618,7 @@
     0xCEE445534C61746Ellu, // ext_Latn_ES
     0x6661495241726162llu, // fa_Arab_IR
     0xB40547514C61746Ellu, // fan_Latn_GQ
+    0x6666474E41646C6Dllu, // ff_Adlm_GN
     0x6666534E4C61746Ellu, // ff_Latn_SN
     0xB0A54D4C4C61746Ellu, // ffm_Latn_ML
     0x666946494C61746Ellu, // fi_Latn_FI
@@ -1020,7 +1633,9 @@
     0xBE2546524C61746Ellu, // frp_Latn_FR
     0xC62544454C61746Ellu, // frr_Latn_DE
     0xCA2544454C61746Ellu, // frs_Latn_DE
+    0x8685434D41726162llu, // fub_Arab_CM
     0x8E8557464C61746Ellu, // fud_Latn_WF
+    0x9685474E4C61746Ellu, // fuf_Latn_GN
     0xC2854E454C61746Ellu, // fuq_Latn_NE
     0xC68549544C61746Ellu, // fur_Latn_IT
     0xD6854E474C61746Ellu, // fuv_Latn_NG
@@ -1104,7 +1719,6 @@
     0x6A614A504A70616Ellu, // ja_Jpan_JP
     0xB0094A4D4C61746Ellu, // jam_Latn_JM
     0xB8C9434D4C61746Ellu, // jgo_Latn_CM
-    0x6A69554148656272llu, // ji_Hebr_UA
     0x8989545A4C61746Ellu, // jmc_Latn_TZ
     0xAD894E5044657661llu, // jml_Deva_NP
     0xCE89444B4C61746Ellu, // jut_Latn_DK
@@ -1118,9 +1732,11 @@
     0xB00A4B454C61746Ellu, // kam_Latn_KE
     0xB80A4D4C4C61746Ellu, // kao_Latn_ML
     0x8C2A52554379726Cllu, // kbd_Cyrl_RU
+    0xE02A4E4541726162llu, // kby_Arab_NE
     0x984A4E474C61746Ellu, // kcg_Latn_NG
     0xA84A5A574C61746Ellu, // kck_Latn_ZW
     0x906A545A4C61746Ellu, // kde_Latn_TZ
+    0x9C6A544741726162llu, // kdh_Arab_TG
     0xCC6A544854686169llu, // kdt_Thai_TH
     0x808A43564C61746Ellu, // kea_Latn_CV
     0xB48A434D4C61746Ellu, // ken_Latn_CM
@@ -1251,7 +1867,7 @@
     0x6D72494E44657661llu, // mr_Deva_IN
     0x8E2C4E5044657661llu, // mrd_Deva_NP
     0xA62C52554379726Cllu, // mrj_Cyrl_RU
-    0xD22C42444D726F6Fllu, // mru_Mroo_BD
+    0xBA2C42444D726F6Fllu, // mro_Mroo_BD
     0x6D734D594C61746Ellu, // ms_Latn_MY
     0x6D744D544C61746Ellu, // mt_Latn_MT
     0xC66C494E44657661llu, // mtr_Deva_IN
@@ -1308,6 +1924,7 @@
     0x6F6D45544C61746Ellu, // om_Latn_ET
     0x6F72494E4F727961llu, // or_Orya_IN
     0x6F7347454379726Cllu, // os_Cyrl_GE
+    0x824E55534F736765llu, // osa_Osge_US
     0xAA6E4D4E4F726B68llu, // otk_Orkh_MN
     0x7061504B41726162llu, // pa_Arab_PK
     0x7061494E47757275llu, // pa_Guru_IN
@@ -1479,6 +2096,7 @@
     0xB2934D574C61746Ellu, // tum_Latn_MW
     0xAEB354564C61746Ellu, // tvl_Latn_TV
     0xC2D34E454C61746Ellu, // twq_Latn_NE
+    0x9AF3434E54616E67llu, // txg_Tang_CN
     0x747950464C61746Ellu, // ty_Latn_PF
     0xD71352554379726Cllu, // tyv_Cyrl_RU
     0xB3334D414C61746Ellu, // tzm_Latn_MA
@@ -1540,14 +2158,18 @@
     0x796F4E474C61746Ellu, // yo_Latn_NG
     0xAE3842524C61746Ellu, // yrl_Latn_BR
     0x82984D584C61746Ellu, // yua_Latn_MX
+    0x9298434E48616E73llu, // yue_Hans_CN
+    0x9298484B48616E74llu, // yue_Hant_HK
     0x7A61434E4C61746Ellu, // za_Latn_CN
     0x981953444C61746Ellu, // zag_Latn_SD
     0xA4794B4D41726162llu, // zdj_Arab_KM
     0x80994E4C4C61746Ellu, // zea_Latn_NL
     0x9CD94D4154666E67llu, // zgh_Tfng_MA
     0x7A685457426F706Fllu, // zh_Bopo_TW
+    0x7A68545748616E62llu, // zh_Hanb_TW
     0x7A68434E48616E73llu, // zh_Hans_CN
     0x7A68545748616E74llu, // zh_Hant_TW
+    0xB17954474C61746Ellu, // zlm_Latn_TG
     0xA1994D594C61746Ellu, // zmi_Latn_MY
     0x7A755A414C61746Ellu, // zu_Latn_ZA
     0x833954524C61746Ellu, // zza_Latn_TR
@@ -1662,6 +2284,7 @@
     {0x656E5A57u, 0x656E8400u}, // en-ZW -> en-001
     {0x65734152u, 0x6573A424u}, // es-AR -> es-419
     {0x6573424Fu, 0x6573A424u}, // es-BO -> es-419
+    {0x65734252u, 0x6573A424u}, // es-BR -> es-419
     {0x6573434Cu, 0x6573A424u}, // es-CL -> es-419
     {0x6573434Fu, 0x6573A424u}, // es-CO -> es-419
     {0x65734352u, 0x6573A424u}, // es-CR -> es-419
@@ -1681,8 +2304,11 @@
     {0x65735559u, 0x6573A424u}, // es-UY -> es-419
     {0x65735645u, 0x6573A424u}, // es-VE -> es-419
     {0x7074414Fu, 0x70745054u}, // pt-AO -> pt-PT
+    {0x70744348u, 0x70745054u}, // pt-CH -> pt-PT
     {0x70744356u, 0x70745054u}, // pt-CV -> pt-PT
+    {0x70744751u, 0x70745054u}, // pt-GQ -> pt-PT
     {0x70744757u, 0x70745054u}, // pt-GW -> pt-PT
+    {0x70744C55u, 0x70745054u}, // pt-LU -> pt-PT
     {0x70744D4Fu, 0x70745054u}, // pt-MO -> pt-PT
     {0x70744D5Au, 0x70745054u}, // pt-MZ -> pt-PT
     {0x70745354u, 0x70745054u}, // pt-ST -> pt-PT
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 7fbfffe..a30c849 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -140,7 +140,7 @@
     patch->colorsOffset = patch->yDivsOffset + (patch->numYDivs * sizeof(int32_t));
 }
 
-inline void Res_value::copyFrom_dtoh(const Res_value& src)
+void Res_value::copyFrom_dtoh(const Res_value& src)
 {
     size = dtohs(src.size);
     res0 = src.res0;
diff --git a/libs/androidfw/include/androidfw/ApkAssets.h b/libs/androidfw/include/androidfw/ApkAssets.h
new file mode 100644
index 0000000..a3d67f0
--- /dev/null
+++ b/libs/androidfw/include/androidfw/ApkAssets.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef APKASSETS_H_
+#define APKASSETS_H_
+
+#include <memory>
+#include <string>
+
+#include "android-base/macros.h"
+#include "ziparchive/zip_archive.h"
+
+#include "androidfw/Asset.h"
+#include "androidfw/LoadedArsc.h"
+
+namespace android {
+
+// Holds an APK.
+class ApkAssets {
+ public:
+  static std::unique_ptr<ApkAssets> Load(const std::string& path);
+
+  std::unique_ptr<Asset> Open(const std::string& path,
+                              Asset::AccessMode mode = Asset::AccessMode::ACCESS_RANDOM) const;
+
+  inline const std::string& GetPath() const { return path_; }
+
+  inline const LoadedArsc* GetLoadedArsc() const { return loaded_arsc_.get(); }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ApkAssets);
+
+  ApkAssets() = default;
+
+  struct ZipArchivePtrCloser {
+    void operator()(::ZipArchiveHandle handle) { ::CloseArchive(handle); }
+  };
+
+  using ZipArchivePtr =
+      std::unique_ptr<typename std::remove_pointer<::ZipArchiveHandle>::type, ZipArchivePtrCloser>;
+  ZipArchivePtr zip_handle_;
+  std::string path_;
+  std::unique_ptr<Asset> resources_asset_;
+  std::unique_ptr<LoadedArsc> loaded_arsc_;
+};
+
+}  // namespace android
+
+#endif /* APKASSETS_H_ */
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
new file mode 100644
index 0000000..66d5034
--- /dev/null
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -0,0 +1,298 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROIDFW_ASSETMANAGER2_H_
+#define ANDROIDFW_ASSETMANAGER2_H_
+
+#include "android-base/macros.h"
+
+#include <limits>
+#include <unordered_map>
+
+#include "androidfw/ApkAssets.h"
+#include "androidfw/Asset.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/ResourceTypes.h"
+#include "androidfw/Util.h"
+
+namespace android {
+
+class Theme;
+
+using ApkAssetsCookie = int32_t;
+
+enum : ApkAssetsCookie {
+  kInvalidCookie = -1,
+};
+
+// Holds a bag that has been merged with its parent, if one exists.
+struct ResolvedBag {
+  // A single key-value entry in a bag.
+  struct Entry {
+    // The key, as described in ResTable_map::name.
+    uint32_t key;
+
+    Res_value value;
+
+    // Which ApkAssets this entry came from.
+    ApkAssetsCookie cookie;
+
+    ResStringPool* key_pool;
+    ResStringPool* type_pool;
+  };
+
+  // Denotes the configuration axis that this bag varies with.
+  // If a configuration changes with respect to one of these axis,
+  // the bag should be reloaded.
+  uint32_t type_spec_flags;
+
+  // The number of entries in this bag. Access them by indexing into `entries`.
+  uint32_t entry_count;
+
+  // The array of entries for this bag. An empty array is a neat trick to force alignment
+  // of the Entry structs that follow this structure and avoids a bunch of casts.
+  Entry entries[0];
+};
+
+// AssetManager2 is the main entry point for accessing assets and resources.
+// AssetManager2 provides caching of resources retrieved via the underlying
+// ApkAssets.
+class AssetManager2 : public ::AAssetManager {
+ public:
+  struct ResourceName {
+    const char* package = nullptr;
+    size_t package_len = 0u;
+
+    const char* type = nullptr;
+    const char16_t* type16 = nullptr;
+    size_t type_len = 0u;
+
+    const char* entry = nullptr;
+    const char16_t* entry16 = nullptr;
+    size_t entry_len = 0u;
+  };
+
+  AssetManager2();
+
+  // Sets/resets the underlying ApkAssets for this AssetManager. The ApkAssets
+  // are not owned by the AssetManager, and must have a longer lifetime.
+  //
+  // Only pass invalidate_caches=false when it is known that the structure
+  // change in ApkAssets is due to a safe addition of resources with completely
+  // new resource IDs.
+  bool SetApkAssets(const std::vector<const ApkAssets*>& apk_assets, bool invalidate_caches = true);
+
+  const std::vector<const ApkAssets*> GetApkAssets() const;
+
+  // Returns the string pool for the given asset cookie.
+  // Use the string pool returned here with a valid Res_value object of
+  // type Res_value::TYPE_STRING.
+  const ResStringPool* GetStringPoolForCookie(ApkAssetsCookie cookie) const;
+
+  // Sets/resets the configuration for this AssetManager. This will cause all
+  // caches that are related to the configuration change to be invalidated.
+  void SetConfiguration(const ResTable_config& configuration);
+
+  const ResTable_config& GetConfiguration() const;
+
+  // Searches the set of APKs loaded by this AssetManager and opens the first one found located
+  // in the assets/ directory.
+  // `mode` controls how the file is opened.
+  //
+  // NOTE: The loaded APKs are searched in reverse order.
+  std::unique_ptr<Asset> Open(const std::string& filename, Asset::AccessMode mode);
+
+  // Opens a file within the assets/ directory of the APK specified by `cookie`.
+  // `mode` controls how the file is opened.
+  std::unique_ptr<Asset> Open(const std::string& filename, ApkAssetsCookie cookie,
+                              Asset::AccessMode mode);
+
+  // Searches the set of APKs loaded by this AssetManager and opens the first one found.
+  // `mode` controls how the file is opened.
+  // `out_cookie` is populated with the cookie of the APK this file was found in.
+  //
+  // NOTE: The loaded APKs are searched in reverse order.
+  std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, Asset::AccessMode mode,
+                                      ApkAssetsCookie* out_cookie = nullptr);
+
+  // Opens a file in the APK specified by `cookie`. `mode` controls how the file is opened.
+  // This is typically used to open a specific AndroidManifest.xml, or a binary XML file
+  // referenced by a resource lookup with GetResource().
+  std::unique_ptr<Asset> OpenNonAsset(const std::string& filename, ApkAssetsCookie cookie,
+                                      Asset::AccessMode mode);
+
+  // Populates the `out_name` parameter with resource name information.
+  // Utf8 strings are preferred, and only if they are unavailable are
+  // the Utf16 variants populated.
+  // Returns false if the resource was not found or the name was missing/corrupt.
+  bool GetResourceName(uint32_t resid, ResourceName* out_name);
+
+  // Populates `out_flags` with the bitmask of configuration axis that this resource varies with.
+  // See ResTable_config for the list of configuration axis.
+  // Returns false if the resource was not found.
+  bool GetResourceFlags(uint32_t resid, uint32_t* out_flags);
+
+  // Retrieves the best matching resource with ID `resid`. The resource value is filled into
+  // `out_value` and the configuration for the selected value is populated in `out_selected_config`.
+  // `out_flags` holds the same flags as retrieved with GetResourceFlags().
+  // If `density_override` is non-zero, the configuration to match against is overridden with that
+  // density.
+  //
+  // Returns a valid cookie if the resource was found. If the resource was not found, or if the
+  // resource was a map/bag type, then kInvalidCookie is returned. If `may_be_bag` is false,
+  // this function logs if the resource was a map/bag type before returning kInvalidCookie.
+  ApkAssetsCookie GetResource(uint32_t resid, bool may_be_bag, uint16_t density_override,
+                              Res_value* out_value, ResTable_config* out_selected_config,
+                              uint32_t* out_flags);
+
+  // Retrieves the best matching bag/map resource with ID `resid`.
+  // This method will resolve all parent references for this bag and merge keys with the child.
+  // To iterate over the keys, use the following idiom:
+  //
+  //  const AssetManager2::ResolvedBag* bag = asset_manager->GetBag(id);
+  //  if (bag != nullptr) {
+  //    for (auto iter = begin(bag); iter != end(bag); ++iter) {
+  //      ...
+  //    }
+  //  }
+  const ResolvedBag* GetBag(uint32_t resid);
+
+  // Creates a new Theme from this AssetManager.
+  std::unique_ptr<Theme> NewTheme();
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(AssetManager2);
+
+  // Finds the best entry for `resid` amongst all the ApkAssets. The entry can be a simple
+  // Res_value, or a complex map/bag type.
+  //
+  // `density_override` overrides the density of the current configuration when doing a search.
+  //
+  // When `stop_at_first_match` is true, the first match found is selected and the search
+  // terminates. This is useful for methods that just look up the name of a resource and don't
+  // care about the value. In this case, the value of `out_flags` is incomplete and should not
+  // be used.
+  //
+  // `out_flags` stores the resulting bitmask of configuration axis with which the resource
+  // value varies.
+  ApkAssetsCookie FindEntry(uint32_t resid, uint16_t density_override, bool stop_at_first_match,
+                            LoadedArsc::Entry* out_entry, ResTable_config* out_selected_config,
+                            uint32_t* out_flags);
+
+  // Purge all resources that are cached and vary by the configuration axis denoted by the
+  // bitmask `diff`.
+  void InvalidateCaches(uint32_t diff);
+
+  // The ordered list of ApkAssets to search. These are not owned by the AssetManager, and must
+  // have a longer lifetime.
+  std::vector<const ApkAssets*> apk_assets_;
+
+  // The current configuration set for this AssetManager. When this changes, cached resources
+  // may need to be purged.
+  ResTable_config configuration_;
+
+  // Cached set of bags. These are cached because they can inherit keys from parent bags,
+  // which involves some calculation.
+  std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
+};
+
+class Theme {
+  friend class AssetManager2;
+
+ public:
+  // Applies the style identified by `resid` to this theme. This can be called
+  // multiple times with different styles. By default, any theme attributes that
+  // are already defined before this call are not overridden. If `force` is set
+  // to true, this behavior is changed and all theme attributes from the style at
+  // `resid` are applied.
+  // Returns false if the style failed to apply.
+  bool ApplyStyle(uint32_t resid, bool force = false);
+
+  // Sets this Theme to be a copy of `o` if `o` has the same AssetManager as this Theme.
+  // Returns false if the AssetManagers of the Themes were not compatible.
+  bool SetTo(const Theme& o);
+
+  void Clear();
+
+  inline const AssetManager2* GetAssetManager() const { return asset_manager_; }
+
+  // Returns a bit mask of configuration changes that will impact this
+  // theme (and thus require completely reloading it).
+  inline uint32_t GetChangingConfigurations() const { return type_spec_flags_; }
+
+  // Retrieve a value in the theme. If the theme defines this value,
+  // returns an asset cookie indicating which ApkAssets it came from
+  // and populates `out_value` with the value. If `out_flags` is non-null,
+  // populates it with a bitmask of the configuration axis the resource
+  // varies with.
+  //
+  // If the attribute is not found, returns kInvalidCookie.
+  //
+  // NOTE: This function does not do reference traversal. If you want
+  // to follow references to other resources to get the "real" value to
+  // use, you need to call ResolveReference() after this function.
+  ApkAssetsCookie GetAttribute(uint32_t resid, Res_value* out_value,
+                               uint32_t* out_flags = nullptr) const;
+
+  // This is like AssetManager2::ResolveReference(), but also takes
+  // care of resolving attribute references to the theme.
+  ApkAssetsCookie ResolveAttributeReference(Res_value* in_out_value, ApkAssetsCookie src_cookie,
+                                            uint32_t* out_last_ref = nullptr,
+                                            uint32_t* in_out_type_spec_flags = nullptr,
+                                            ResTable_config* out_selected_config = nullptr) const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(Theme);
+
+  // Called by AssetManager2.
+  explicit inline Theme(AssetManager2* asset_manager) : asset_manager_(asset_manager) {}
+
+  struct Entry {
+    ApkAssetsCookie cookie;
+    uint32_t type_spec_flags;
+    Res_value value;
+  };
+
+  struct Type {
+    // Use uint32_t for fewer cycles when loading from memory.
+    uint32_t entry_count;
+    uint32_t entry_capacity;
+    Entry entries[0];
+  };
+
+  static constexpr const size_t kPackageCount = std::numeric_limits<uint8_t>::max() + 1;
+  static constexpr const size_t kTypeCount = std::numeric_limits<uint8_t>::max() + 1;
+
+  struct Package {
+    // Each element of Type will be a dynamically sized object
+    // allocated to have the entries stored contiguously with the Type.
+    util::unique_cptr<Type> types[kTypeCount];
+  };
+
+  AssetManager2* asset_manager_;
+  uint32_t type_spec_flags_ = 0u;
+  std::unique_ptr<Package> packages_[kPackageCount];
+};
+
+inline const ResolvedBag::Entry* begin(const ResolvedBag* bag) { return bag->entries; }
+
+inline const ResolvedBag::Entry* end(const ResolvedBag* bag) {
+  return bag->entries + bag->entry_count;
+}
+
+}  // namespace android
+
+#endif /* ANDROIDFW_ASSETMANAGER2_H_ */
diff --git a/libs/androidfw/include/androidfw/ByteBucketArray.h b/libs/androidfw/include/androidfw/ByteBucketArray.h
index 87c6b12..d84a207 100644
--- a/libs/androidfw/include/androidfw/ByteBucketArray.h
+++ b/libs/androidfw/include/androidfw/ByteBucketArray.h
@@ -17,9 +17,10 @@
 #ifndef __BYTE_BUCKET_ARRAY_H
 #define __BYTE_BUCKET_ARRAY_H
 
-#include <utils/Log.h>
-#include <stdint.h>
-#include <string.h>
+#include <cstdint>
+#include <cstring>
+
+#include "android-base/logging.h"
 
 namespace android {
 
@@ -27,71 +28,65 @@
  * Stores a sparsely populated array. Has a fixed size of 256
  * (number of entries that a byte can represent).
  */
-template<typename T>
+template <typename T>
 class ByteBucketArray {
-public:
-    ByteBucketArray() : mDefault() {
-        memset(mBuckets, 0, sizeof(mBuckets));
+ public:
+  ByteBucketArray() : default_() { memset(buckets_, 0, sizeof(buckets_)); }
+
+  ~ByteBucketArray() {
+    for (size_t i = 0; i < kNumBuckets; i++) {
+      if (buckets_[i] != NULL) {
+        delete[] buckets_[i];
+      }
+    }
+    memset(buckets_, 0, sizeof(buckets_));
+  }
+
+  inline size_t size() const { return kNumBuckets * kBucketSize; }
+
+  inline const T& get(size_t index) const { return (*this)[index]; }
+
+  const T& operator[](size_t index) const {
+    if (index >= size()) {
+      return default_;
     }
 
-    ~ByteBucketArray() {
-        for (size_t i = 0; i < NUM_BUCKETS; i++) {
-            if (mBuckets[i] != NULL) {
-                delete [] mBuckets[i];
-            }
-        }
-        memset(mBuckets, 0, sizeof(mBuckets));
+    uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
+    T* bucket = buckets_[bucket_index];
+    if (bucket == NULL) {
+      return default_;
+    }
+    return bucket[0x0f & static_cast<uint8_t>(index)];
+  }
+
+  T& editItemAt(size_t index) {
+    CHECK(index < size()) << "ByteBucketArray.getOrCreate(index=" << index
+                          << ") with size=" << size();
+
+    uint8_t bucket_index = static_cast<uint8_t>(index) >> 4;
+    T* bucket = buckets_[bucket_index];
+    if (bucket == NULL) {
+      bucket = buckets_[bucket_index] = new T[kBucketSize]();
+    }
+    return bucket[0x0f & static_cast<uint8_t>(index)];
+  }
+
+  bool set(size_t index, const T& value) {
+    if (index >= size()) {
+      return false;
     }
 
-    inline size_t size() const {
-        return NUM_BUCKETS * BUCKET_SIZE;
-    }
+    editItemAt(index) = value;
+    return true;
+  }
 
-    inline const T& get(size_t index) const {
-        return (*this)[index];
-    }
+ private:
+  enum { kNumBuckets = 16, kBucketSize = 16 };
 
-    const T& operator[](size_t index) const {
-        if (index >= size()) {
-            return mDefault;
-        }
-
-        uint8_t bucketIndex = static_cast<uint8_t>(index) >> 4;
-        T* bucket = mBuckets[bucketIndex];
-        if (bucket == NULL) {
-            return mDefault;
-        }
-        return bucket[0x0f & static_cast<uint8_t>(index)];
-    }
-
-    T& editItemAt(size_t index) {
-        ALOG_ASSERT(index < size(), "ByteBucketArray.getOrCreate(index=%u) with size=%u",
-                (uint32_t) index, (uint32_t) size());
-
-        uint8_t bucketIndex = static_cast<uint8_t>(index) >> 4;
-        T* bucket = mBuckets[bucketIndex];
-        if (bucket == NULL) {
-            bucket = mBuckets[bucketIndex] = new T[BUCKET_SIZE]();
-        }
-        return bucket[0x0f & static_cast<uint8_t>(index)];
-    }
-
-    bool set(size_t index, const T& value) {
-        if (index >= size()) {
-            return false;
-        }
-
-        editItemAt(index) = value;
-        return true;
-    }
-
-private:
-    enum { NUM_BUCKETS = 16, BUCKET_SIZE = 16 };
-
-    T*  mBuckets[NUM_BUCKETS];
-    T   mDefault;
+  T* buckets_[kNumBuckets];
+  T default_;
 };
 
-} // namespace android
+}  // namespace android
 
-#endif // __BYTE_BUCKET_ARRAY_H
+#endif  // __BYTE_BUCKET_ARRAY_H
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
new file mode 100644
index 0000000..e2e56c8
--- /dev/null
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+#ifndef LOADEDARSC_H_
+#define LOADEDARSC_H_
+
+#include <memory>
+#include <vector>
+
+#include "android-base/macros.h"
+
+#include "androidfw/ResourceTypes.h"
+
+namespace android {
+
+class Chunk;
+class LoadedPackage;
+
+// Read-only view into a resource table. This class validates all data
+// when loading, including offsets and lengths.
+class LoadedArsc {
+ public:
+  // Load the resource table from memory. The data's lifetime must out-live the
+  // object returned from this method.
+  static std::unique_ptr<LoadedArsc> Load(const void* data, size_t len);
+
+  ~LoadedArsc();
+
+  // Returns the string pool where all string resource values
+  // (Res_value::dataType == Res_value::TYPE_STRING) are indexed.
+  inline const ResStringPool* GetStringPool() const { return &global_string_pool_; }
+
+  struct Entry {
+    // A pointer to the resource table entry for this resource.
+    // If the size of the entry is > sizeof(ResTable_entry), it can be cast to
+    // a ResTable_map_entry and processed as a bag/map.
+    const ResTable_entry* entry = nullptr;
+
+    // The string pool reference to the type's name. This uses a different string pool than
+    // the global string pool, but this is hidden from the caller.
+    StringPoolRef type_string_ref;
+
+    // The string pool reference to the entry's name. This uses a different string pool than
+    // the global string pool, but this is hidden from the caller.
+    StringPoolRef entry_string_ref;
+  };
+
+  // Finds the resource with ID `resid` with the best value for configuration `config`.
+  // The parameter `out_entry` will be filled with the resulting resource entry.
+  // The resource entry can be a simple entry (ResTable_entry) or a complex bag
+  // (ResTable_entry_map).
+  bool FindEntry(uint32_t resid, const ResTable_config& config, Entry* out_entry,
+                 ResTable_config* selected_config, uint32_t* out_flags) const;
+
+  // Gets a pointer to the name of the package in `resid`, or nullptr if the package doesn't exist.
+  const std::string* GetPackageNameForId(uint32_t resid) const;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(LoadedArsc);
+
+  LoadedArsc() = default;
+  bool LoadTable(const Chunk& chunk);
+
+  ResStringPool global_string_pool_;
+  std::vector<std::unique_ptr<LoadedPackage>> packages_;
+};
+
+}  // namespace android
+
+#endif /* LOADEDARSC_H_ */
diff --git a/libs/androidfw/include/androidfw/ResourceTypes.h b/libs/androidfw/include/androidfw/ResourceTypes.h
index 33b91b9..c118b57 100644
--- a/libs/androidfw/include/androidfw/ResourceTypes.h
+++ b/libs/androidfw/include/androidfw/ResourceTypes.h
@@ -265,7 +265,7 @@
     uint8_t res0;
         
     // Type of the data value.
-    enum {
+    enum : uint8_t {
         // The 'data' is either 0 or 1, specifying this resource is either
         // undefined or empty, respectively.
         TYPE_NULL = 0x00,
diff --git a/libs/androidfw/include/androidfw/Util.h b/libs/androidfw/include/androidfw/Util.h
new file mode 100644
index 0000000..5266d09
--- /dev/null
+++ b/libs/androidfw/include/androidfw/Util.h
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+#ifndef UTIL_H_
+#define UTIL_H_
+
+#include <cstdlib>
+#include <memory>
+
+#include "android-base/macros.h"
+
+namespace android {
+namespace util {
+
+/**
+ * Makes a std::unique_ptr<> with the template parameter inferred by the
+ * compiler.
+ * This will be present in C++14 and can be removed then.
+ */
+template <typename T, class... Args>
+std::unique_ptr<T> make_unique(Args&&... args) {
+  return std::unique_ptr<T>(new T{std::forward<Args>(args)...});
+}
+
+// Based on std::unique_ptr, but uses free() to release malloc'ed memory
+// without incurring the size increase of holding on to a custom deleter.
+template <typename T>
+class unique_cptr {
+ public:
+  using pointer = typename std::add_pointer<T>::type;
+
+  constexpr unique_cptr() : ptr_(nullptr) {}
+  constexpr unique_cptr(std::nullptr_t) : ptr_(nullptr) {}
+  explicit unique_cptr(pointer ptr) : ptr_(ptr) {}
+  unique_cptr(unique_cptr&& o) : ptr_(o.ptr_) { o.ptr_ = nullptr; }
+
+  ~unique_cptr() { std::free(reinterpret_cast<void*>(ptr_)); }
+
+  inline unique_cptr& operator=(unique_cptr&& o) {
+    if (&o == this) {
+      return *this;
+    }
+
+    std::free(reinterpret_cast<void*>(ptr_));
+    ptr_ = o.ptr_;
+    o.ptr_ = nullptr;
+    return *this;
+  }
+
+  inline unique_cptr& operator=(std::nullptr_t) {
+    std::free(reinterpret_cast<void*>(ptr_));
+    ptr_ = nullptr;
+    return *this;
+  }
+
+  pointer release() {
+    pointer result = ptr_;
+    ptr_ = nullptr;
+    return result;
+  }
+
+  inline pointer get() const { return ptr_; }
+
+  void reset(pointer ptr = pointer()) {
+    if (ptr == ptr_) {
+      return;
+    }
+
+    pointer old_ptr = ptr_;
+    ptr_ = ptr;
+    std::free(reinterpret_cast<void*>(old_ptr));
+  }
+
+  inline void swap(unique_cptr& o) { std::swap(ptr_, o.ptr_); }
+
+  inline explicit operator bool() const { return ptr_ != nullptr; }
+
+  inline typename std::add_lvalue_reference<T>::type operator*() const { return *ptr_; }
+
+  inline pointer operator->() const { return ptr_; }
+
+  inline bool operator==(const unique_cptr& o) const { return ptr_ == o.ptr_; }
+
+  inline bool operator==(std::nullptr_t) const { return ptr_ == nullptr; }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(unique_cptr);
+
+  pointer ptr_;
+};
+
+inline uint8_t get_package_id(uint32_t resid) {
+  return static_cast<uint8_t>((resid >> 24) & 0x000000ffu);
+}
+
+// The type ID is 1-based, so if the returned value is 0 it is invalid.
+inline uint8_t get_type_id(uint32_t resid) {
+  return static_cast<uint8_t>((resid >> 16) & 0x000000ffu);
+}
+
+inline uint16_t get_entry_id(uint32_t resid) { return static_cast<uint16_t>(resid & 0x0000ffffu); }
+
+inline bool is_internal_id(uint32_t resid) {
+  return (resid & 0xffff0000u) != 0 && (resid & 0x00ff0000u) == 0;
+}
+
+inline bool is_valid_resid(uint32_t resid) {
+  return (resid & 0x00ff0000u) != 0 && (resid & 0xff000000u) != 0;
+}
+
+}  // namespace util
+}  // namespace android
+
+#endif /* UTIL_H_ */
diff --git a/libs/androidfw/tests/Android.mk b/libs/androidfw/tests/Android.mk
index d91a133..6754cd8 100644
--- a/libs/androidfw/tests/Android.mk
+++ b/libs/androidfw/tests/Android.mk
@@ -21,22 +21,31 @@
 LOCAL_PATH:= $(call my-dir)
 
 testFiles := \
+    ApkAssets_test.cpp \
     AppAsLib_test.cpp \
     Asset_test.cpp \
+    AssetManager2_test.cpp \
     AttributeFinder_test.cpp \
     AttributeResolution_test.cpp \
     ByteBucketArray_test.cpp \
     Config_test.cpp \
     ConfigLocale_test.cpp \
     Idmap_test.cpp \
-    Main.cpp \
+    LoadedArsc_test.cpp \
     ResTable_test.cpp \
     Split_test.cpp \
     TestHelpers.cpp \
+    TestMain.cpp \
     Theme_test.cpp \
     TypeWrappers_test.cpp \
     ZipUtils_test.cpp
 
+benchmarkFiles := \
+    AssetManager2_bench.cpp \
+    BenchMain.cpp \
+    TestHelpers.cpp \
+    Theme_bench.cpp
+
 androidfw_test_cflags := \
     -Wall \
     -Werror \
@@ -89,5 +98,25 @@
 LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
 
 include $(BUILD_NATIVE_TEST)
+
+# ==========================================================
+# Build the device benchmarks: libandroidfw_benchmarks
+# ==========================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libandroidfw_benchmarks
+LOCAL_CFLAGS := $(androidfw_test_cflags)
+LOCAL_SRC_FILES := $(benchmarkFiles)
+LOCAL_STATIC_LIBRARIES := \
+    libgoogle-benchmark
+LOCAL_SHARED_LIBRARIES := \
+    libandroidfw \
+    libbase \
+    libcutils \
+    libutils \
+    libziparchive
+LOCAL_PICKUP_FILES := $(LOCAL_PATH)/data
+
+include $(BUILD_NATIVE_TEST)
 endif # Not SDK_ONLY
 
diff --git a/libs/androidfw/tests/ApkAssets_test.cpp b/libs/androidfw/tests/ApkAssets_test.cpp
new file mode 100644
index 0000000..3a1fc8f
--- /dev/null
+++ b/libs/androidfw/tests/ApkAssets_test.cpp
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#include "androidfw/ApkAssets.h"
+
+#include "TestHelpers.h"
+#include "data/basic/R.h"
+
+using com::android::basic::R;
+
+namespace android {
+
+TEST(ApkAssetsTest, LoadApk) {
+  std::unique_ptr<ApkAssets> loaded_apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+  ASSERT_NE(nullptr, loaded_apk);
+
+  std::unique_ptr<Asset> asset = loaded_apk->Open("res/layout/main.xml");
+  ASSERT_NE(nullptr, asset);
+}
+
+}  // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_bench.cpp b/libs/androidfw/tests/AssetManager2_bench.cpp
new file mode 100644
index 0000000..9ff9478
--- /dev/null
+++ b/libs/androidfw/tests/AssetManager2_bench.cpp
@@ -0,0 +1,228 @@
+/*
+ * 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.
+ */
+
+#include "benchmark/benchmark.h"
+
+#include "androidfw/ApkAssets.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/AssetManager2.h"
+#include "androidfw/ResourceTypes.h"
+
+#include "TestHelpers.h"
+#include "data/basic/R.h"
+#include "data/styles/R.h"
+
+namespace basic = com::android::basic;
+namespace app = com::android::app;
+
+namespace android {
+
+constexpr const static char* kFrameworkPath = "/system/framework/framework-res.apk";
+
+static void BM_AssetManagerLoadAssets(benchmark::State& state) {
+  std::string path = GetTestDataPath() + "/basic/basic.apk";
+  while (state.KeepRunning()) {
+    std::unique_ptr<ApkAssets> apk = ApkAssets::Load(path);
+    AssetManager2 assets;
+    assets.SetApkAssets({apk.get()});
+  }
+}
+BENCHMARK(BM_AssetManagerLoadAssets);
+
+static void BM_AssetManagerLoadAssetsOld(benchmark::State& state) {
+  String8 path((GetTestDataPath() + "/basic/basic.apk").data());
+  while (state.KeepRunning()) {
+    AssetManager assets;
+    assets.addAssetPath(path, nullptr /* cookie */, false /* appAsLib */,
+                        false /* isSystemAsset */);
+
+    // Force creation.
+    assets.getResources(true);
+  }
+}
+BENCHMARK(BM_AssetManagerLoadAssetsOld);
+
+static void BM_AssetManagerLoadFrameworkAssets(benchmark::State& state) {
+  std::string path = kFrameworkPath;
+  while (state.KeepRunning()) {
+    std::unique_ptr<ApkAssets> apk = ApkAssets::Load(path);
+    AssetManager2 assets;
+    assets.SetApkAssets({apk.get()});
+  }
+}
+BENCHMARK(BM_AssetManagerLoadFrameworkAssets);
+
+static void BM_AssetManagerLoadFrameworkAssetsOld(benchmark::State& state) {
+  String8 path(kFrameworkPath);
+  while (state.KeepRunning()) {
+    AssetManager assets;
+    assets.addAssetPath(path, nullptr /* cookie */, false /* appAsLib */,
+                        false /* isSystemAsset */);
+
+    // Force creation.
+    assets.getResources(true);
+  }
+}
+BENCHMARK(BM_AssetManagerLoadFrameworkAssetsOld);
+
+static void BM_AssetManagerGetResource(benchmark::State& state) {
+  std::unique_ptr<ApkAssets> apk = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+  if (apk == nullptr) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    assets.GetResource(basic::R::integer::number1, false /* may_be_bag */,
+                       0u /* density_override */, &value, &selected_config, &flags);
+  }
+}
+BENCHMARK(BM_AssetManagerGetResource);
+
+static void BM_AssetManagerGetResourceOld(benchmark::State& state) {
+  AssetManager assets;
+  if (!assets.addAssetPath(String8((GetTestDataPath() + "/basic/basic.apk").data()),
+                           nullptr /* cookie */, false /* appAsLib */,
+                           false /* isSystemAssets */)) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  const ResTable& table = assets.getResources(true);
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    table.getResource(basic::R::integer::number1, &value, false /* may_be_bag */,
+                      0u /* density_override */, &flags, &selected_config);
+  }
+}
+BENCHMARK(BM_AssetManagerGetResourceOld);
+
+constexpr static const uint32_t kStringOkId = 0x0104000au;
+
+static void BM_AssetManagerGetResourceFrameworkLocale(benchmark::State& state) {
+  std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+  if (apk == nullptr) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  memcpy(config.language, "fr", 2);
+  assets.SetConfiguration(config);
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    assets.GetResource(kStringOkId, false /* may_be_bag */, 0u /* density_override */, &value,
+                       &selected_config, &flags);
+  }
+}
+BENCHMARK(BM_AssetManagerGetResourceFrameworkLocale);
+
+static void BM_AssetManagerGetResourceFrameworkLocaleOld(benchmark::State& state) {
+  AssetManager assets;
+  if (!assets.addAssetPath(String8((GetTestDataPath() + "/basic/basic.apk").data()),
+                           nullptr /* cookie */, false /* appAsLib */,
+                           false /* isSystemAssets */)) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  memcpy(config.language, "fr", 2);
+  assets.setConfiguration(config, nullptr);
+
+  const ResTable& table = assets.getResources(true);
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    table.getResource(kStringOkId, &value, false /* may_be_bag */, 0u /* density_override */,
+                      &flags, &selected_config);
+  }
+}
+BENCHMARK(BM_AssetManagerGetResourceFrameworkLocaleOld);
+
+static void BM_AssetManagerGetBag(benchmark::State& state) {
+  std::unique_ptr<ApkAssets> apk = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+  if (apk == nullptr) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  while (state.KeepRunning()) {
+    const ResolvedBag* bag = assets.GetBag(app::R::style::StyleTwo);
+    const auto bag_end = end(bag);
+    for (auto iter = begin(bag); iter != bag_end; ++iter) {
+      uint32_t key = iter->key;
+      Res_value value = iter->value;
+      benchmark::DoNotOptimize(key);
+      benchmark::DoNotOptimize(value);
+    }
+  }
+}
+BENCHMARK(BM_AssetManagerGetBag);
+
+static void BM_AssetManagerGetBagOld(benchmark::State& state) {
+  AssetManager assets;
+  if (!assets.addAssetPath(String8((GetTestDataPath() + "/styles/styles.apk").data()),
+                           nullptr /* cookie */, false /* appAsLib */,
+                           false /* isSystemAssets */)) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  const ResTable& table = assets.getResources(true);
+
+  while (state.KeepRunning()) {
+    const ResTable::bag_entry* bag_begin;
+    const ssize_t N = table.lockBag(app::R::style::StyleTwo, &bag_begin);
+    const ResTable::bag_entry* const bag_end = bag_begin + N;
+    for (auto iter = bag_begin; iter != bag_end; ++iter) {
+      uint32_t key = iter->map.name.ident;
+      Res_value value = iter->map.value;
+      benchmark::DoNotOptimize(key);
+      benchmark::DoNotOptimize(value);
+    }
+    table.unlockBag(bag_begin);
+  }
+}
+BENCHMARK(BM_AssetManagerGetBagOld);
+
+}  // namespace android
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
new file mode 100644
index 0000000..39c5381
--- /dev/null
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -0,0 +1,190 @@
+/*
+ * 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.
+ */
+
+#include "androidfw/AssetManager2.h"
+#include "androidfw/AssetManager.h"
+
+#include "android-base/logging.h"
+
+#include "TestHelpers.h"
+#include "data/basic/R.h"
+#include "data/styles/R.h"
+
+namespace basic = com::android::basic;
+namespace app = com::android::app;
+
+namespace android {
+
+class AssetManager2Test : public ::testing::Test {
+ public:
+  void SetUp() override {
+    basic_assets_ = ApkAssets::Load(GetTestDataPath() + "/basic/basic.apk");
+    ASSERT_NE(nullptr, basic_assets_);
+
+    basic_de_fr_assets_ = ApkAssets::Load(GetTestDataPath() + "/basic/basic_de_fr.apk");
+    ASSERT_NE(nullptr, basic_de_fr_assets_);
+
+    style_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+    ASSERT_NE(nullptr, style_assets_);
+  }
+
+ protected:
+  std::unique_ptr<ApkAssets> basic_assets_;
+  std::unique_ptr<ApkAssets> basic_de_fr_assets_;
+  std::unique_ptr<ApkAssets> style_assets_;
+};
+
+TEST_F(AssetManager2Test, FindsResourcesFromSingleApkAssets) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  AssetManager2 assetmanager;
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get()});
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  // Came from our ApkAssets.
+  EXPECT_EQ(0, cookie);
+
+  // It is the default config.
+  EXPECT_EQ(0, selected_config.language[0]);
+  EXPECT_EQ(0, selected_config.language[1]);
+
+  // It is a string.
+  EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+}
+
+TEST_F(AssetManager2Test, FindsResourcesFromMultipleApkAssets) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  AssetManager2 assetmanager;
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({basic_assets_.get(), basic_de_fr_assets_.get()});
+
+  Res_value value;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ApkAssetsCookie cookie =
+      assetmanager.GetResource(basic::R::string::test1, false /*may_be_bag*/,
+                               0 /*density_override*/, &value, &selected_config, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+
+  // Came from our de_fr ApkAssets.
+  EXPECT_EQ(1, cookie);
+
+  // The configuration is german.
+  EXPECT_EQ('d', selected_config.language[0]);
+  EXPECT_EQ('e', selected_config.language[1]);
+
+  // It is a string.
+  EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+}
+
+TEST_F(AssetManager2Test, FindsBagResourcesFromSingleApkAssets) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({basic_assets_.get()});
+
+  const ResolvedBag* bag = assetmanager.GetBag(basic::R::array::integerArray1);
+  ASSERT_NE(nullptr, bag);
+  ASSERT_EQ(3u, bag->entry_count);
+
+  EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[0].value.dataType);
+  EXPECT_EQ(1u, bag->entries[0].value.data);
+  EXPECT_EQ(0, bag->entries[0].cookie);
+
+  EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[1].value.dataType);
+  EXPECT_EQ(2u, bag->entries[1].value.data);
+  EXPECT_EQ(0, bag->entries[1].cookie);
+
+  EXPECT_EQ(static_cast<uint8_t>(Res_value::TYPE_INT_DEC), bag->entries[2].value.dataType);
+  EXPECT_EQ(3u, bag->entries[2].value.data);
+  EXPECT_EQ(0, bag->entries[2].cookie);
+}
+
+TEST_F(AssetManager2Test, MergesStylesWithParentFromSingleApkAssets) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  const ResolvedBag* bag_one = assetmanager.GetBag(app::R::style::StyleOne);
+  ASSERT_NE(nullptr, bag_one);
+  ASSERT_EQ(2u, bag_one->entry_count);
+
+  EXPECT_EQ(app::R::attr::attr_one, bag_one->entries[0].key);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_one->entries[0].value.dataType);
+  EXPECT_EQ(1u, bag_one->entries[0].value.data);
+  EXPECT_EQ(0, bag_one->entries[0].cookie);
+
+  EXPECT_EQ(app::R::attr::attr_two, bag_one->entries[1].key);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_one->entries[1].value.dataType);
+  EXPECT_EQ(2u, bag_one->entries[1].value.data);
+  EXPECT_EQ(0, bag_one->entries[1].cookie);
+
+  const ResolvedBag* bag_two = assetmanager.GetBag(app::R::style::StyleTwo);
+  ASSERT_NE(nullptr, bag_two);
+  ASSERT_EQ(5u, bag_two->entry_count);
+
+  // attr_one is inherited from StyleOne.
+  EXPECT_EQ(app::R::attr::attr_one, bag_two->entries[0].key);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[0].value.dataType);
+  EXPECT_EQ(1u, bag_two->entries[0].value.data);
+  EXPECT_EQ(0, bag_two->entries[0].cookie);
+
+  // attr_two should be overridden from StyleOne by StyleTwo.
+  EXPECT_EQ(app::R::attr::attr_two, bag_two->entries[1].key);
+  EXPECT_EQ(Res_value::TYPE_STRING, bag_two->entries[1].value.dataType);
+  EXPECT_EQ(0, bag_two->entries[1].cookie);
+  EXPECT_EQ(std::string("string"), GetStringFromPool(assetmanager.GetStringPoolForCookie(0),
+                                                     bag_two->entries[1].value.data));
+
+  // The rest are new attributes.
+
+  EXPECT_EQ(app::R::attr::attr_three, bag_two->entries[2].key);
+  EXPECT_EQ(Res_value::TYPE_ATTRIBUTE, bag_two->entries[2].value.dataType);
+  EXPECT_EQ(app::R::attr::attr_indirect, bag_two->entries[2].value.data);
+  EXPECT_EQ(0, bag_two->entries[2].cookie);
+
+  EXPECT_EQ(app::R::attr::attr_five, bag_two->entries[3].key);
+  EXPECT_EQ(Res_value::TYPE_REFERENCE, bag_two->entries[3].value.dataType);
+  EXPECT_EQ(app::R::string::string_one, bag_two->entries[3].value.data);
+  EXPECT_EQ(0, bag_two->entries[3].cookie);
+
+  EXPECT_EQ(app::R::attr::attr_indirect, bag_two->entries[4].key);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, bag_two->entries[4].value.dataType);
+  EXPECT_EQ(3u, bag_two->entries[4].value.data);
+  EXPECT_EQ(0, bag_two->entries[4].cookie);
+}
+
+TEST_F(AssetManager2Test, FindsBagResourcesFromMultipleApkAssets) {}
+
+TEST_F(AssetManager2Test, OpensFileFromSingleApkAssets) {}
+
+TEST_F(AssetManager2Test, OpensFileFromMultipleApkAssets) {}
+
+}  // namespace android
diff --git a/libs/androidfw/tests/AttributeResolution_test.cpp b/libs/androidfw/tests/AttributeResolution_test.cpp
index 7550517..1ff2ed4 100644
--- a/libs/androidfw/tests/AttributeResolution_test.cpp
+++ b/libs/androidfw/tests/AttributeResolution_test.cpp
@@ -205,4 +205,5 @@
   EXPECT_EQ(public_flag, values_cursor[STYLE_CHANGING_CONFIGURATIONS]);
 }
 
-}  // namespace android
+} // namespace android
+
diff --git a/libs/androidfw/tests/BenchMain.cpp b/libs/androidfw/tests/BenchMain.cpp
new file mode 100644
index 0000000..105c5f9
--- /dev/null
+++ b/libs/androidfw/tests/BenchMain.cpp
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+
+#include "benchmark/benchmark.h"
+
+#include "TestHelpers.h"
+
+int main(int argc, char** argv) {
+  ::benchmark::Initialize(&argc, argv);
+  ::android::InitializeTest(&argc, argv);
+
+  std::cerr << "using --testdata=" << ::android::GetTestDataPath() << "\n";
+
+  size_t result = ::benchmark::RunSpecifiedBenchmarks();
+  return result == 0 ? 1 : 0;
+}
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
new file mode 100644
index 0000000..47b3894
--- /dev/null
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -0,0 +1,82 @@
+/*
+ * 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.
+ */
+
+#include "androidfw/LoadedArsc.h"
+
+#include "android-base/file.h"
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+
+#include "TestHelpers.h"
+#include "data/basic/R.h"
+#include "data/styles/R.h"
+
+namespace app = com::android::app;
+namespace basic = com::android::basic;
+
+namespace android {
+
+TEST(LoadedArscTest, LoadSinglePackageArsc) {
+  base::ScopedLogSeverity _log(base::LogSeverity::DEBUG);
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/styles/styles.apk", "resources.arsc",
+                                      &contents));
+
+  std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  ResTable_config config;
+  memset(&config, 0, sizeof(config));
+  config.sdkVersion = 24;
+
+  LoadedArsc::Entry entry;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ASSERT_TRUE(
+      loaded_arsc->FindEntry(app::R::string::string_one, config, &entry, &selected_config, &flags));
+  ASSERT_NE(nullptr, entry.entry);
+}
+
+TEST(LoadedArscTest, FindDefaultEntry) {
+  base::ScopedLogSeverity _log(base::LogSeverity::DEBUG);
+  std::string contents;
+  ASSERT_TRUE(
+      ReadFileFromZipToString(GetTestDataPath() + "/basic/basic.apk", "resources.arsc", &contents));
+
+  std::unique_ptr<LoadedArsc> loaded_arsc = LoadedArsc::Load(contents.data(), contents.size());
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+  desired_config.language[0] = 'd';
+  desired_config.language[1] = 'e';
+
+  LoadedArsc::Entry entry;
+  ResTable_config selected_config;
+  uint32_t flags;
+
+  ASSERT_TRUE(loaded_arsc->FindEntry(basic::R::string::test1, desired_config, &entry,
+                                     &selected_config, &flags));
+  ASSERT_NE(nullptr, entry.entry);
+}
+
+// structs with size fields (like Res_value, ResTable_entry) should be
+// backwards and forwards compatible (aka checking the size field against
+// sizeof(Res_value) might not be backwards compatible.
+TEST(LoadedArscTest, LoadingShouldBeForwardsAndBackwardsCompatible) { ASSERT_TRUE(false); }
+
+}  // namespace android
diff --git a/libs/androidfw/tests/Main.cpp b/libs/androidfw/tests/Main.cpp
deleted file mode 100644
index 6a50691..0000000
--- a/libs/androidfw/tests/Main.cpp
+++ /dev/null
@@ -1,69 +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.
- */
-
-#include <libgen.h>
-
-#include <iostream>
-#include <memory>
-#include <string>
-
-#include "android-base/file.h"
-#include "android-base/strings.h"
-#include "gtest/gtest.h"
-
-#include "TestHelpers.h"
-
-// Extract the directory of the current executable path.
-static std::string GetExecutableDir() {
-  const std::string path = android::base::GetExecutablePath();
-  std::unique_ptr<char, decltype(&std::free)> mutable_path = {
-      strdup(path.c_str()), std::free};
-  std::string executable_dir = dirname(mutable_path.get());
-  return executable_dir;
-}
-
-int main(int argc, char** argv) {
-  ::testing::InitGoogleTest(&argc, argv);
-
-  // Set the default test data path to be the executable path directory.
-  android::SetTestDataPath(GetExecutableDir());
-
-  const char* command = argv[0];
-  ++argv;
-  --argc;
-
-  while (argc > 0) {
-    const std::string arg = *argv;
-    if (android::base::StartsWith(arg, "--testdata=")) {
-      android::SetTestDataPath(arg.substr(strlen("--testdata=")));
-    } else if (arg == "-h" || arg == "--help") {
-      std::cerr
-          << "\nAdditional options specific to this test:\n"
-             "  --testdata=[PATH]\n"
-             "      Specify the location of test data used within the tests.\n";
-      return 1;
-    } else {
-      std::cerr << command << ": Unrecognized argument '" << *argv << "'.\n";
-      return 1;
-    }
-
-    --argc;
-    ++argv;
-  }
-
-  std::cerr << "using --testdata=" << android::GetTestDataPath() << "\n";
-  return RUN_ALL_TESTS();
-}
diff --git a/libs/androidfw/tests/TestHelpers.cpp b/libs/androidfw/tests/TestHelpers.cpp
index 2c834b1..1e763a5 100644
--- a/libs/androidfw/tests/TestHelpers.cpp
+++ b/libs/androidfw/tests/TestHelpers.cpp
@@ -16,15 +16,51 @@
 
 #include "TestHelpers.h"
 
+#include <libgen.h>
 #include <unistd.h>
 
+#include <memory>
+#include <string>
+
+#include "android-base/file.h"
 #include "android-base/logging.h"
+#include "android-base/strings.h"
 #include "ziparchive/zip_archive.h"
 
 namespace android {
 
 static std::string sTestDataPath;
 
+// Extract the directory of the current executable path.
+static std::string GetExecutableDir() {
+  const std::string path = base::GetExecutablePath();
+  std::unique_ptr<char, decltype(&std::free)> mutable_path = {strdup(path.c_str()), std::free};
+  std::string executable_dir = dirname(mutable_path.get());
+  return executable_dir;
+}
+
+void InitializeTest(int* argc, char** argv) {
+  // Set the default test data path to be the executable path directory.
+  SetTestDataPath(GetExecutableDir());
+
+  for (int i = 1; i < *argc; i++) {
+    const std::string arg = argv[i];
+    if (base::StartsWith(arg, "--testdata=")) {
+      SetTestDataPath(arg.substr(strlen("--testdata=")));
+      for (int j = i; j != *argc; j++) {
+        argv[j] = argv[j + 1];
+      }
+      --(*argc);
+      --i;
+    } else if (arg == "-h" || arg == "--help") {
+      std::cerr << "\nAdditional options specific to this test:\n"
+                   "  --testdata=[PATH]\n"
+                   "      Specify the location of test data used within the tests.\n";
+      exit(1);
+    }
+  }
+}
+
 void SetTestDataPath(const std::string& path) { sTestDataPath = path; }
 
 const std::string& GetTestDataPath() {
@@ -90,4 +126,9 @@
   return ::testing::AssertionSuccess() << actual_str.string();
 }
 
+std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx) {
+  String8 str = pool->string8ObjectAt(idx);
+  return std::string(str.string(), str.length());
+}
+
 }  // namespace android
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index d9cee22..a11ea84 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -35,6 +35,8 @@
 
 namespace android {
 
+void InitializeTest(int* argc, char** argv);
+
 enum { MAY_NOT_BE_BAG = false };
 
 void SetTestDataPath(const std::string& path);
@@ -56,6 +58,8 @@
 ::testing::AssertionResult IsStringEqual(const ResTable& table, uint32_t resource_id,
                                          const char* expected_str);
 
+std::string GetStringFromPool(const ResStringPool* pool, uint32_t idx);
+
 }  // namespace android
 
 #endif  // TEST_HELPERS_H_
diff --git a/libs/androidfw/tests/TestMain.cpp b/libs/androidfw/tests/TestMain.cpp
new file mode 100644
index 0000000..d1c0f60
--- /dev/null
+++ b/libs/androidfw/tests/TestMain.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#include <iostream>
+
+#include "TestHelpers.h"
+
+int main(int argc, char** argv) {
+  ::testing::InitGoogleTest(&argc, argv);
+  ::android::InitializeTest(&argc, argv);
+
+  std::cerr << "using --testdata=" << ::android::GetTestDataPath() << "\n";
+
+  return RUN_ALL_TESTS();
+}
diff --git a/libs/androidfw/tests/Theme_bench.cpp b/libs/androidfw/tests/Theme_bench.cpp
new file mode 100644
index 0000000..c471be6
--- /dev/null
+++ b/libs/androidfw/tests/Theme_bench.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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.
+ */
+
+#include "benchmark/benchmark.h"
+
+#include "androidfw/ApkAssets.h"
+#include "androidfw/AssetManager.h"
+#include "androidfw/AssetManager2.h"
+#include "androidfw/ResourceTypes.h"
+
+namespace android {
+
+constexpr const static char* kFrameworkPath = "/system/framework/framework-res.apk";
+constexpr const static uint32_t kStyleId = 0x01030237u;  // android:style/Theme.Material.Light
+constexpr const static uint32_t kAttrId = 0x01010030u;   // android:attr/colorForeground
+
+static void BM_ThemeApplyStyleFramework(benchmark::State& state) {
+  std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+  if (apk == nullptr) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  while (state.KeepRunning()) {
+    auto theme = assets.NewTheme();
+    theme->ApplyStyle(kStyleId, false /* force */);
+  }
+}
+BENCHMARK(BM_ThemeApplyStyleFramework);
+
+static void BM_ThemeApplyStyleFrameworkOld(benchmark::State& state) {
+  AssetManager assets;
+  if (!assets.addAssetPath(String8(kFrameworkPath), nullptr /* cookie */, false /* appAsLib */,
+                           true /* isSystemAsset */)) {
+    state.SkipWithError("Failed to load assets");
+    return;
+  }
+
+  const ResTable& res_table = assets.getResources(true);
+
+  while (state.KeepRunning()) {
+    std::unique_ptr<ResTable::Theme> theme{new ResTable::Theme(res_table)};
+    theme->applyStyle(kStyleId, false /* force */);
+  }
+}
+BENCHMARK(BM_ThemeApplyStyleFrameworkOld);
+
+static void BM_ThemeGetAttribute(benchmark::State& state) {
+  std::unique_ptr<ApkAssets> apk = ApkAssets::Load(kFrameworkPath);
+
+  AssetManager2 assets;
+  assets.SetApkAssets({apk.get()});
+
+  auto theme = assets.NewTheme();
+  theme->ApplyStyle(kStyleId, false /* force */);
+
+  Res_value value;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    theme->GetAttribute(kAttrId, &value, &flags);
+  }
+}
+BENCHMARK(BM_ThemeGetAttribute);
+
+static void BM_ThemeGetAttributeOld(benchmark::State& state) {
+  AssetManager assets;
+  assets.addAssetPath(String8(kFrameworkPath), nullptr /* cookie */, false /* appAsLib */,
+                      true /* isSystemAsset */);
+  const ResTable& res_table = assets.getResources(true);
+  std::unique_ptr<ResTable::Theme> theme{new ResTable::Theme(res_table)};
+  theme->applyStyle(kStyleId, false /* force */);
+
+  Res_value value;
+  uint32_t flags;
+
+  while (state.KeepRunning()) {
+    theme->getAttribute(kAttrId, &value, &flags);
+  }
+}
+BENCHMARK(BM_ThemeGetAttributeOld);
+
+}  // namespace android
diff --git a/libs/androidfw/tests/Theme_test.cpp b/libs/androidfw/tests/Theme_test.cpp
index 3774657..c0011b6d 100644
--- a/libs/androidfw/tests/Theme_test.cpp
+++ b/libs/androidfw/tests/Theme_test.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -14,59 +14,221 @@
  * limitations under the License.
  */
 
-#include "androidfw/ResourceTypes.h"
+#include "androidfw/AssetManager2.h"
 
-#include "utils/String16.h"
-#include "utils/String8.h"
+#include "android-base/logging.h"
 
 #include "TestHelpers.h"
-#include "data/app/R.h"
-#include "data/system/R.h"
+#include "data/styles/R.h"
 
 namespace app = com::android::app;
 
 namespace android {
 
-/**
- * TODO(adamlesinski): Enable when fixed.
- */
-TEST(ThemeTest, DISABLED_shouldCopyThemeFromDifferentResTable) {
-  ResTable table;
+class ThemeTest : public ::testing::Test {
+ public:
+  void SetUp() override {
+    style_assets_ = ApkAssets::Load(GetTestDataPath() + "/styles/styles.apk");
+    ASSERT_NE(nullptr, style_assets_);
+  }
 
-  std::string system_contents;
-  ASSERT_TRUE(ReadFileFromZipToString("/system/system.apk", "resources.arsc",
-                                      &system_contents));
-  ASSERT_EQ(NO_ERROR,
-            table.add(system_contents.data(), system_contents.size()));
+ protected:
+  std::unique_ptr<ApkAssets> style_assets_;
+};
 
-  std::string app_contents;
-  ASSERT_TRUE(ReadFileFromZipToString("/basic/basic.apk", "resources.arsc",
-                                      &app_contents));
-  ASSERT_EQ(NO_ERROR, table.add(app_contents.data(), app_contents.size()));
+TEST_F(ThemeTest, EmptyTheme) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
 
-  ResTable::Theme theme1(table);
-  ASSERT_EQ(NO_ERROR, theme1.applyStyle(app::R::style::Theme_One));
-  Res_value val;
-  ASSERT_GE(theme1.getAttribute(android::R::attr::background, &val), 0);
-  ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
-  ASSERT_EQ(uint32_t(0xffff0000), val.data);
-  ASSERT_GE(theme1.getAttribute(app::R::attr::number, &val), 0);
-  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-  ASSERT_EQ(uint32_t(1), val.data);
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  EXPECT_EQ(0u, theme->GetChangingConfigurations());
+  EXPECT_EQ(&assetmanager, theme->GetAssetManager());
 
-  ResTable table2;
-  ASSERT_EQ(NO_ERROR,
-            table2.add(system_contents.data(), system_contents.size()));
-  ASSERT_EQ(NO_ERROR, table2.add(app_contents.data(), app_contents.size()));
+  Res_value value;
+  uint32_t flags;
+  EXPECT_EQ(kInvalidCookie, theme->GetAttribute(app::R::attr::attr_one, &value, &flags));
+}
 
-  ResTable::Theme theme2(table2);
-  ASSERT_EQ(NO_ERROR, theme2.setTo(theme1));
-  ASSERT_GE(theme2.getAttribute(android::R::attr::background, &val), 0);
-  ASSERT_EQ(Res_value::TYPE_INT_COLOR_RGB8, val.dataType);
-  ASSERT_EQ(uint32_t(0xffff0000), val.data);
-  ASSERT_GE(theme2.getAttribute(app::R::attr::number, &val), 0);
-  ASSERT_EQ(Res_value::TYPE_INT_DEC, val.dataType);
-  ASSERT_EQ(uint32_t(1), val.data);
+TEST_F(ThemeTest, SingleThemeNoParent) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleOne));
+
+  Res_value value;
+  uint32_t flags;
+  ApkAssetsCookie cookie;
+
+  cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(1u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  cookie = theme->GetAttribute(app::R::attr::attr_two, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(2u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+}
+
+TEST_F(ThemeTest, SingleThemeWithParent) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
+
+  Res_value value;
+  uint32_t flags;
+  ApkAssetsCookie cookie;
+
+  cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(1u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  cookie = theme->GetAttribute(app::R::attr::attr_two, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_STRING, value.dataType);
+  EXPECT_EQ(0, cookie);
+  EXPECT_EQ(std::string("string"),
+            GetStringFromPool(assetmanager.GetStringPoolForCookie(0), value.data));
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // This attribute should point to an attr_indirect, so the result should be 3.
+  cookie = theme->GetAttribute(app::R::attr::attr_three, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(3u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+}
+
+TEST_F(ThemeTest, MultipleThemesOverlaidNotForce) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree));
+
+  Res_value value;
+  uint32_t flags;
+  ApkAssetsCookie cookie;
+
+  // attr_one is still here from the base.
+  cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(1u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // check for the new attr_six
+  cookie = theme->GetAttribute(app::R::attr::attr_six, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(6u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // check for the old attr_five (force=true was not used).
+  cookie = theme->GetAttribute(app::R::attr::attr_five, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_REFERENCE, value.dataType);
+  EXPECT_EQ(app::R::string::string_one, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+}
+
+TEST_F(ThemeTest, MultipleThemesOverlaidForced) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme = assetmanager.NewTheme();
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleTwo));
+  ASSERT_TRUE(theme->ApplyStyle(app::R::style::StyleThree, true /* force */));
+
+  Res_value value;
+  uint32_t flags;
+  ApkAssetsCookie cookie;
+
+  // attr_one is still here from the base.
+  cookie = theme->GetAttribute(app::R::attr::attr_one, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(1u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // check for the new attr_six
+  cookie = theme->GetAttribute(app::R::attr::attr_six, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(6u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // check for the new attr_five (force=true was used).
+  cookie = theme->GetAttribute(app::R::attr::attr_five, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(5u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+}
+
+TEST_F(ThemeTest, CopyThemeSameAssetManager) {
+  AssetManager2 assetmanager;
+  assetmanager.SetApkAssets({style_assets_.get()});
+
+  std::unique_ptr<Theme> theme_one = assetmanager.NewTheme();
+  ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
+
+  Res_value value;
+  uint32_t flags;
+  ApkAssetsCookie cookie;
+
+  // attr_one is still here from the base.
+  cookie = theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(1u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+
+  // attr_six is not here.
+  EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_six, &value, &flags));
+
+  std::unique_ptr<Theme> theme_two = assetmanager.NewTheme();
+  ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleThree));
+
+  // Copy the theme to theme_one.
+  ASSERT_TRUE(theme_one->SetTo(*theme_two));
+
+  // Clear theme_two to make sure we test that there WAS a copy.
+  theme_two->Clear();
+
+  // attr_one is now not here.
+  EXPECT_EQ(kInvalidCookie, theme_one->GetAttribute(app::R::attr::attr_one, &value, &flags));
+
+  // attr_six is now here because it was copied.
+  cookie = theme_one->GetAttribute(app::R::attr::attr_six, &value, &flags);
+  ASSERT_NE(kInvalidCookie, cookie);
+  EXPECT_EQ(Res_value::TYPE_INT_DEC, value.dataType);
+  EXPECT_EQ(6u, value.data);
+  EXPECT_EQ(static_cast<uint32_t>(ResTable_typeSpec::SPEC_PUBLIC), flags);
+}
+
+TEST_F(ThemeTest, FailToCopyThemeWithDifferentAssetManager) {
+  AssetManager2 assetmanager_one;
+  assetmanager_one.SetApkAssets({style_assets_.get()});
+
+  AssetManager2 assetmanager_two;
+  assetmanager_two.SetApkAssets({style_assets_.get()});
+
+  auto theme_one = assetmanager_one.NewTheme();
+  ASSERT_TRUE(theme_one->ApplyStyle(app::R::style::StyleOne));
+
+  auto theme_two = assetmanager_two.NewTheme();
+  ASSERT_TRUE(theme_two->ApplyStyle(app::R::style::StyleTwo));
+
+  EXPECT_FALSE(theme_one->SetTo(*theme_two));
 }
 
 }  // namespace android
diff --git a/libs/androidfw/tests/data/styles/R.h b/libs/androidfw/tests/data/styles/R.h
index 4127aa0..68527c7 100644
--- a/libs/androidfw/tests/data/styles/R.h
+++ b/libs/androidfw/tests/data/styles/R.h
@@ -32,6 +32,7 @@
       attr_four = 0x7f010003u,
       attr_five = 0x7f010004u,
       attr_indirect = 0x7f010005u,
+      attr_six = 0x7f010006u,
     };
   };
 
@@ -45,6 +46,7 @@
     enum : uint32_t {
       StyleOne = 0x7f020000u,
       StyleTwo = 0x7f020001u,
+      StyleThree = 0x7f020002u,
     };
   };
 };
diff --git a/libs/androidfw/tests/data/styles/res/values/styles.xml b/libs/androidfw/tests/data/styles/res/values/styles.xml
index 70c54f6..da592f8 100644
--- a/libs/androidfw/tests/data/styles/res/values/styles.xml
+++ b/libs/androidfw/tests/data/styles/res/values/styles.xml
@@ -39,6 +39,7 @@
     <public type="style" name="StyleOne" id="0x7f020000" />
     <style name="StyleOne">
         <item name="attr_one">1</item>
+        <item name="attr_two">2</item>
     </style>
 
     <public type="style" name="StyleTwo" id="0x7f020001" />
@@ -48,5 +49,14 @@
         <item name="attr_three">?attr/attr_indirect</item>
         <item name="attr_five">@string/string_one</item>
     </style>
+    
+    <public type="attr" name="attr_six" id="0x7f010006" />
+    <attr name="attr_six" />
+    
+    <public type="style" name="StyleThree" id="0x7f020002" />
+    <style name="StyleThree">
+        <item name="attr_six">6</item>
+        <item name="attr_five">5</item>
+    </style>
 
 </resources>
diff --git a/libs/androidfw/tests/data/styles/styles.apk b/libs/androidfw/tests/data/styles/styles.apk
index 6064c48..d4ccb83 100644
--- a/libs/androidfw/tests/data/styles/styles.apk
+++ b/libs/androidfw/tests/data/styles/styles.apk
Binary files differ
diff --git a/libs/hwui/DeferredLayerUpdater.cpp b/libs/hwui/DeferredLayerUpdater.cpp
index 3e8e8a1..0ae50e9 100644
--- a/libs/hwui/DeferredLayerUpdater.cpp
+++ b/libs/hwui/DeferredLayerUpdater.cpp
@@ -131,7 +131,7 @@
                         mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
 
     static const mat4 identityMatrix;
-    updateLayer(false, identityMatrix.data);
+    updateLayer(false, GL_NONE, identityMatrix.data);
 
     VkLayer* vkLayer = static_cast<VkLayer*>(mLayer);
     vkLayer->updateTexture();
@@ -139,26 +139,20 @@
 
 void DeferredLayerUpdater::updateLayer(bool forceFilter, GLenum renderTarget,
         const float* textureTransform) {
-    LOG_ALWAYS_FATAL_IF(mLayer->getApi() != Layer::Api::OpenGL,
-                        "updateLayer non GL backend %x, GL %x, VK %x",
-                        mLayer->getApi(), Layer::Api::OpenGL, Layer::Api::Vulkan);
-
-    updateLayer(forceFilter, textureTransform);
-
-    GlLayer* glLayer = static_cast<GlLayer*>(mLayer);
-    if (renderTarget != glLayer->getRenderTarget()) {
-        glLayer->setRenderTarget(renderTarget);
-        glLayer->bindTexture();
-        glLayer->setFilter(GL_NEAREST, false, true);
-        glLayer->setWrap(GL_CLAMP_TO_EDGE, false, true);
-    }
-}
-
-void DeferredLayerUpdater::updateLayer(bool forceFilter, const float* textureTransform) {
     mLayer->setBlend(mBlend);
     mLayer->setForceFilter(forceFilter);
     mLayer->setSize(mWidth, mHeight);
     mLayer->getTexTransform().load(textureTransform);
+
+    if (mLayer->getApi() == Layer::Api::OpenGL) {
+        GlLayer* glLayer = static_cast<GlLayer*>(mLayer);
+        if (renderTarget != glLayer->getRenderTarget()) {
+            glLayer->setRenderTarget(renderTarget);
+            glLayer->bindTexture();
+            glLayer->setFilter(GL_NEAREST, false, true);
+            glLayer->setWrap(GL_CLAMP_TO_EDGE, false, true);
+        }
+    }
 }
 
 void DeferredLayerUpdater::detachSurfaceTexture() {
diff --git a/libs/hwui/DeferredLayerUpdater.h b/libs/hwui/DeferredLayerUpdater.h
index ead8314..3814be2 100644
--- a/libs/hwui/DeferredLayerUpdater.h
+++ b/libs/hwui/DeferredLayerUpdater.h
@@ -114,7 +114,6 @@
 
     void doUpdateTexImage();
     void doUpdateVkTexImage();
-    void updateLayer(bool forceFilter, const float* textureTransform);
 };
 
 } /* namespace uirenderer */
diff --git a/libs/hwui/Properties.cpp b/libs/hwui/Properties.cpp
index 0702010..09e34bf 100644
--- a/libs/hwui/Properties.cpp
+++ b/libs/hwui/Properties.cpp
@@ -222,6 +222,12 @@
     return sRenderPipelineType;
 }
 
+#ifdef HWUI_GLES_WRAP_ENABLED
+void Properties::overrideRenderPipelineType(RenderPipelineType type) {
+    sRenderPipelineType = type;
+}
+#endif
+
 bool Properties::isSkiaEnabled() {
     auto renderType = getRenderPipelineType();
     return RenderPipelineType::SkiaGL == renderType
diff --git a/libs/hwui/Properties.h b/libs/hwui/Properties.h
index b4a3118..6dc0cb3 100644
--- a/libs/hwui/Properties.h
+++ b/libs/hwui/Properties.h
@@ -318,11 +318,15 @@
     // any overhead they add
     static bool filterOutTestOverhead;
 
+    // Used for testing only to change the render pipeline.
+#ifdef HWUI_GLES_WRAP_ENABLED
+    static void overrideRenderPipelineType(RenderPipelineType);
+#endif
+
 private:
     static ProfileType sProfileType;
     static bool sDisableProfileBars;
     static RenderPipelineType sRenderPipelineType;
-
 }; // class Caches
 
 }; // namespace uirenderer
diff --git a/libs/hwui/SkiaCanvas.cpp b/libs/hwui/SkiaCanvas.cpp
index 344df0a..89e2a01 100644
--- a/libs/hwui/SkiaCanvas.cpp
+++ b/libs/hwui/SkiaCanvas.cpp
@@ -24,7 +24,6 @@
 #include "pipeline/skia/AnimatedDrawables.h"
 
 #include <SkDrawable.h>
-#include <SkDevice.h>
 #include <SkDeque.h>
 #include <SkDrawFilter.h>
 #include <SkGraphics.h>
diff --git a/libs/hwui/tests/common/TestUtils.cpp b/libs/hwui/tests/common/TestUtils.cpp
index 5f6bcb3..275ce16 100644
--- a/libs/hwui/tests/common/TestUtils.cpp
+++ b/libs/hwui/tests/common/TestUtils.cpp
@@ -21,6 +21,9 @@
 
 #include <renderthread/EglManager.h>
 #include <renderthread/OpenGLPipeline.h>
+#include <pipeline/skia/SkiaOpenGLPipeline.h>
+#include <pipeline/skia/SkiaVulkanPipeline.h>
+#include <renderthread/VulkanManager.h>
 #include <utils/Unicode.h>
 #include <SkClipStack.h>
 
@@ -47,10 +50,24 @@
 }
 
 sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
+        renderthread::RenderThread& renderThread) {
+    android::uirenderer::renderthread::IRenderPipeline* pipeline;
+    if (Properties::getRenderPipelineType() == RenderPipelineType::OpenGL) {
+        pipeline = new renderthread::OpenGLPipeline(renderThread);
+    } else if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
+        pipeline = new skiapipeline::SkiaOpenGLPipeline(renderThread);
+    } else {
+        pipeline = new skiapipeline::SkiaVulkanPipeline(renderThread);
+    }
+    sp<DeferredLayerUpdater> layerUpdater = pipeline->createTextureLayer();
+    delete pipeline;
+    return layerUpdater;
+}
+
+sp<DeferredLayerUpdater> TestUtils::createTextureLayerUpdater(
         renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
         const SkMatrix& transform) {
-    renderthread::OpenGLPipeline pipeline(renderThread);
-    sp<DeferredLayerUpdater> layerUpdater = pipeline.createTextureLayer();
+    sp<DeferredLayerUpdater> layerUpdater = createTextureLayerUpdater(renderThread);
     layerUpdater->backingLayer()->getTransform().load(transform);
     layerUpdater->setSize(width, height);
     layerUpdater->setTransform(&transform);
@@ -111,12 +128,20 @@
 void TestUtils::TestTask::run() {
     // RenderState only valid once RenderThread is running, so queried here
     renderthread::RenderThread& renderThread = renderthread::RenderThread::getInstance();
-    renderThread.eglManager().initialize();
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+        renderThread.vulkanManager().initialize();
+    } else {
+        renderThread.eglManager().initialize();
+    }
 
     rtCallback(renderThread);
 
-    renderThread.renderState().flush(Caches::FlushMode::Full);
-    renderThread.eglManager().destroy();
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+        renderThread.vulkanManager().destroy();
+    } else {
+        renderThread.renderState().flush(Caches::FlushMode::Full);
+        renderThread.eglManager().destroy();
+    }
 }
 
 std::unique_ptr<uint16_t[]> TestUtils::asciiToUtf16(const char* str) {
diff --git a/libs/hwui/tests/common/TestUtils.h b/libs/hwui/tests/common/TestUtils.h
index 80cbb24..8b287de 100644
--- a/libs/hwui/tests/common/TestUtils.h
+++ b/libs/hwui/tests/common/TestUtils.h
@@ -19,6 +19,7 @@
 #include <DeviceInfo.h>
 #include <DisplayList.h>
 #include <Matrix.h>
+#include <Properties.h>
 #include <Rect.h>
 #include <RenderNode.h>
 #include <hwui/Bitmap.h>
@@ -51,6 +52,31 @@
         } else { \
             ADD_FAILURE() << "ClipState not a rect"; \
         }
+
+#define INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, functionCall) \
+    TEST(test_case_name, test_name##_##pipeline) { \
+        RenderPipelineType oldType = Properties::getRenderPipelineType(); \
+        Properties::overrideRenderPipelineType(RenderPipelineType::pipeline); \
+        functionCall; \
+        Properties::overrideRenderPipelineType(oldType); \
+    };
+
+/**
+ * Like gtests' TEST, but only runs with the OpenGL RenderPipelineType
+ */
+#define OPENGL_PIPELINE_TEST(test_case_name, test_name) \
+    class test_case_name##_##test_name##_HwuiTest { \
+    public: \
+        static void doTheThing(); \
+    }; \
+    INNER_PIPELINE_TEST(test_case_name, test_name, OpenGL, \
+            test_case_name##_##test_name##_HwuiTest::doTheThing()) \
+    void test_case_name##_##test_name##_HwuiTest::doTheThing()
+
+#define INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, pipeline) \
+    INNER_PIPELINE_TEST(test_case_name, test_name, pipeline, \
+            TestUtils::runOnRenderThread(test_case_name##_##test_name##_RenderThreadTest::doTheThing))
+
 /**
  * Like gtest's TEST, but runs on the RenderThread, and 'renderThread' is passed, in top level scope
  * (for e.g. accessing its RenderState)
@@ -60,9 +86,32 @@
     public: \
         static void doTheThing(renderthread::RenderThread& renderThread); \
     }; \
-    TEST(test_case_name, test_name) { \
-        TestUtils::runOnRenderThread(test_case_name##_##test_name##_RenderThreadTest::doTheThing); \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); \
+    void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
+
+/**
+ * Like RENDERTHREAD_TEST, but only runs with the OpenGL RenderPipelineType
+ */
+#define RENDERTHREAD_OPENGL_PIPELINE_TEST(test_case_name, test_name) \
+    class test_case_name##_##test_name##_RenderThreadTest { \
+    public: \
+        static void doTheThing(renderthread::RenderThread& renderThread); \
     }; \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, OpenGL); \
+    void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
+
+/**
+ * Like RENDERTHREAD_TEST, but only runs with the Skia RenderPipelineTypes
+ */
+#define RENDERTHREAD_SKIA_PIPELINE_TEST(test_case_name, test_name) \
+    class test_case_name##_##test_name##_RenderThreadTest { \
+    public: \
+        static void doTheThing(renderthread::RenderThread& renderThread); \
+    }; \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaGL); \
+    INNER_PIPELINE_RENDERTHREAD_TEST(test_case_name, test_name, SkiaVulkan); \
     void test_case_name##_##test_name##_RenderThreadTest::doTheThing(renderthread::RenderThread& renderThread)
 
 /**
@@ -137,6 +186,9 @@
     }
 
     static sp<DeferredLayerUpdater> createTextureLayerUpdater(
+            renderthread::RenderThread& renderThread);
+
+    static sp<DeferredLayerUpdater> createTextureLayerUpdater(
             renderthread::RenderThread& renderThread, uint32_t width, uint32_t height,
             const SkMatrix& transform);
 
diff --git a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
index d44be7d..9a3b81c 100644
--- a/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpDispatcherTests.cpp
@@ -80,7 +80,7 @@
             << "Glop(s) expected";
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, pathTexture_positionOvalArc) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTexture_positionOvalArc) {
     SkPaint strokePaint;
     strokePaint.setStyle(SkPaint::kStroke_Style);
     strokePaint.setStrokeWidth(4);
@@ -113,7 +113,7 @@
     testUnmergedGlopDispatch(renderThread, &ovalOp, textureGlopVerifier);
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, onLayerOp_bufferless) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, onLayerOp_bufferless) {
     SkPaint layerPaint;
     layerPaint.setAlpha(128);
     OffscreenBuffer* buffer = nullptr; // no providing a buffer, should hit rect fallback case
@@ -131,7 +131,7 @@
     return result;
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, offsetFlags) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, offsetFlags) {
     Rect bounds(10, 15, 20, 25);
     SkPaint paint;
     SkPaint aaPaint;
@@ -157,7 +157,7 @@
             << "Expect an offset for non-AA lines.";
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, renderTextWithShadow) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, renderTextWithShadow) {
     auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
             [](RenderProperties& props, RecordingCanvas& canvas) {
 
@@ -232,7 +232,7 @@
     return c;
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, layerUpdateProperties) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, layerUpdateProperties) {
     for (bool debugOverdraw : { false, true }) {
         for (bool debugLayersUpdates : { false, true }) {
             ScopedProperty<bool> ovdProp(Properties::debugOverdraw, debugOverdraw);
@@ -273,7 +273,7 @@
     }
 }
 
-RENDERTHREAD_TEST(BakedOpDispatcher, pathTextureSnapping) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpDispatcher, pathTextureSnapping) {
     Rect bounds(10, 15, 20, 25);
     SkPaint paint;
     SkPath path;
diff --git a/libs/hwui/tests/unit/BakedOpRendererTests.cpp b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
index 59bd75e..380062a 100644
--- a/libs/hwui/tests/unit/BakedOpRendererTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpRendererTests.cpp
@@ -23,7 +23,7 @@
 
 const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
 
-RENDERTHREAD_TEST(BakedOpRenderer, startRepaintLayer_clear) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(BakedOpRenderer, startRepaintLayer_clear) {
     BakedOpRenderer renderer(Caches::getInstance(), renderThread.renderState(), true, sLightInfo);
     OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200u, 200u);
 
diff --git a/libs/hwui/tests/unit/CanvasContextTests.cpp b/libs/hwui/tests/unit/CanvasContextTests.cpp
index d3d80a9..42ba3db 100644
--- a/libs/hwui/tests/unit/CanvasContextTests.cpp
+++ b/libs/hwui/tests/unit/CanvasContextTests.cpp
@@ -46,5 +46,10 @@
 RENDERTHREAD_TEST(CanvasContext, invokeFunctor) {
     TestUtils::MockFunctor functor;
     CanvasContext::invokeFunctor(renderThread, &functor);
-    ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeProcess);
+    if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
+        // we currently don't support OpenGL WebViews on the Vulkan backend
+        ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeProcessNoContext);
+    } else {
+        ASSERT_EQ(functor.getLastMode(), DrawGlInfo::kModeProcess);
+    }
 }
diff --git a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
index f1b8882..1ef9dba 100644
--- a/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
+++ b/libs/hwui/tests/unit/DeferredLayerUpdaterTests.cpp
@@ -16,8 +16,8 @@
 
 #include "DeferredLayerUpdater.h"
 #include "GlLayer.h"
+#include "Properties.h"
 
-#include "renderthread/OpenGLPipeline.h"
 #include "tests/common/TestUtils.h"
 
 #include <gtest/gtest.h>
@@ -26,12 +26,10 @@
 using namespace android::uirenderer;
 
 RENDERTHREAD_TEST(DeferredLayerUpdater, updateLayer) {
-    renderthread::OpenGLPipeline pipeline(renderThread);
-    sp<DeferredLayerUpdater> layerUpdater = pipeline.createTextureLayer();
+    sp<DeferredLayerUpdater> layerUpdater = TestUtils::createTextureLayerUpdater(renderThread);
     layerUpdater->setSize(100, 100);
     layerUpdater->setBlend(true);
 
-
     // updates are deferred so the backing layer should still be in its default state
     if (layerUpdater->backingLayer()->getApi() == Layer::Api::OpenGL) {
         GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
diff --git a/libs/hwui/tests/unit/DeviceInfoTests.cpp b/libs/hwui/tests/unit/DeviceInfoTests.cpp
index 17236bd..af37938 100644
--- a/libs/hwui/tests/unit/DeviceInfoTests.cpp
+++ b/libs/hwui/tests/unit/DeviceInfoTests.cpp
@@ -17,11 +17,12 @@
 #include <DeviceInfo.h>
 
 #include <gtest/gtest.h>
+#include "tests/common/TestUtils.h"
 
 using namespace android;
 using namespace android::uirenderer;
 
-TEST(DeviceInfo, basic) {
+OPENGL_PIPELINE_TEST(DeviceInfo, basic) {
     // can't assert state before init - another test may have initialized the singleton
     DeviceInfo::initialize();
     const DeviceInfo* di = DeviceInfo::get();
diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp
index 99080ac..ee20236 100644
--- a/libs/hwui/tests/unit/FontRendererTests.cpp
+++ b/libs/hwui/tests/unit/FontRendererTests.cpp
@@ -28,7 +28,7 @@
     return true;
 }
 
-RENDERTHREAD_TEST(FontRenderer, renderDropShadow) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FontRenderer, renderDropShadow) {
     SkPaint paint;
     paint.setTextSize(10);
     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
diff --git a/libs/hwui/tests/unit/FrameBuilderTests.cpp b/libs/hwui/tests/unit/FrameBuilderTests.cpp
index 71c7516..6f3ed9c 100644
--- a/libs/hwui/tests/unit/FrameBuilderTests.cpp
+++ b/libs/hwui/tests/unit/FrameBuilderTests.cpp
@@ -109,7 +109,7 @@
 
 class FailRenderer : public TestRendererBase {};
 
-RENDERTHREAD_TEST(FrameBuilder, simple) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simple) {
     class SimpleTestRenderer : public TestRendererBase {
     public:
         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
@@ -143,7 +143,7 @@
     EXPECT_EQ(4, renderer.getIndex()); // 2 ops + start + end
 }
 
-RENDERTHREAD_TEST(FrameBuilder, simpleStroke) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleStroke) {
     class SimpleStrokeTestRenderer : public TestRendererBase {
     public:
         void onPointsOp(const PointsOp& op, const BakedOpState& state) override {
@@ -171,7 +171,7 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, simpleRejection) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleRejection) {
     auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
@@ -187,7 +187,7 @@
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, simpleBatching) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, simpleBatching) {
     const int LOOPS = 5;
     class SimpleBatchingTestRenderer : public TestRendererBase {
     public:
@@ -225,7 +225,7 @@
             << "Expect number of ops = 2 * loop count";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, deferRenderNode_translateClip) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNode_translateClip) {
     class DeferRenderNodeTranslateClipTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -251,7 +251,7 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, deferRenderNodeScene) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferRenderNodeScene) {
     class DeferRenderNodeSceneTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -320,7 +320,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, empty_noFbo0) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, empty_noFbo0) {
     class EmptyNoFbo0TestRenderer : public TestRendererBase {
     public:
         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
@@ -338,7 +338,7 @@
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, empty_withFbo0) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, empty_withFbo0) {
     class EmptyWithFbo0TestRenderer : public TestRendererBase {
     public:
         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
@@ -364,7 +364,7 @@
             " but fbo0 update lifecycle should still be observed";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_rects) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_rects) {
     class AvoidOverdrawRectsTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -394,7 +394,7 @@
     EXPECT_EQ(1, renderer.getIndex()) << "Expect exactly one op";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, avoidOverdraw_bitmaps) {
     static sk_sp<Bitmap> opaqueBitmap(TestUtils::createBitmap(50, 50,
             SkColorType::kRGB_565_SkColorType));
     static sk_sp<Bitmap> transpBitmap(TestUtils::createBitmap(50, 50,
@@ -437,7 +437,7 @@
     EXPECT_EQ(2, renderer.getIndex()) << "Expect exactly two ops";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, clippedMerging) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clippedMerging) {
     class ClippedMergingTestRenderer : public TestRendererBase {
     public:
         void onMergedBitmapOps(const MergedBakedOpList& opList) override {
@@ -479,7 +479,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, regionClipStopsMerge) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, regionClipStopsMerge) {
     class RegionClipStopsMergeTestRenderer : public TestRendererBase {
     public:
         void onTextOp(const TextOp& op, const BakedOpState& state) override { mIndex++; }
@@ -508,7 +508,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textMerging) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textMerging) {
     class TextMergingTestRenderer : public TestRendererBase {
     public:
         void onMergedTextOps(const MergedBakedOpList& opList) override {
@@ -538,7 +538,7 @@
     EXPECT_EQ(2, renderer.getIndex()) << "Expect 2 ops";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textStrikethrough) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStrikethrough) {
     const int LOOPS = 5;
     class TextStrikethroughTestRenderer : public TestRendererBase {
     public:
@@ -576,7 +576,7 @@
 static auto styles = {
         SkPaint::kFill_Style, SkPaint::kStroke_Style, SkPaint::kStrokeAndFill_Style };
 
-RENDERTHREAD_TEST(FrameBuilder, textStyle) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textStyle) {
     class TextStyleTestRenderer : public TestRendererBase {
     public:
         void onMergedTextOps(const MergedBakedOpList& opList) override {
@@ -630,7 +630,7 @@
     EXPECT_EQ(3, renderer.getIndex()) << "Expect 3 ops";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_clipLocalMatrix) {
     class TextureLayerClipLocalMatrixTestRenderer : public TestRendererBase {
     public:
         void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
@@ -664,7 +664,7 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textureLayer_combineMatrices) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_combineMatrices) {
     class TextureLayerCombineMatricesTestRenderer : public TestRendererBase {
     public:
         void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
@@ -696,10 +696,10 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, textureLayer_reject) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, textureLayer_reject) {
     auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
             SkMatrix::MakeTrans(5, 5));
-    if (layerUpdater->backingLayer()->getApi() != Layer::Api::OpenGL) return;
+    EXPECT_EQ(Layer::Api::OpenGL, layerUpdater->backingLayer()->getApi());
 
     GlLayer* glLayer = static_cast<GlLayer*>(layerUpdater->backingLayer());
     glLayer->setRenderTarget(GL_NONE); // Should be rejected
@@ -717,7 +717,7 @@
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, functor_reject) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, functor_reject) {
     class FunctorTestRenderer : public TestRendererBase {
     public:
         void onFunctorOp(const FunctorOp& op, const BakedOpState& state) override {
@@ -742,7 +742,7 @@
     EXPECT_EQ(1, renderer.getIndex()) << "Functor should not be rejected";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, deferColorOp_unbounded) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, deferColorOp_unbounded) {
     class ColorTestRenderer : public TestRendererBase {
     public:
         void onColorOp(const ColorOp& op, const BakedOpState& state) override {
@@ -767,7 +767,7 @@
     EXPECT_EQ(1, renderer.getIndex()) << "ColorOp should not be rejected";
 }
 
-TEST(FrameBuilder, renderNode) {
+OPENGL_PIPELINE_TEST(FrameBuilder, renderNode) {
     class RenderNodeTestRenderer : public TestRendererBase {
     public:
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -814,7 +814,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, clipped) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clipped) {
     class ClippedTestRenderer : public TestRendererBase {
     public:
         void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
@@ -840,7 +840,7 @@
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayer_simple) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_simple) {
     class SaveLayerSimpleTestRenderer : public TestRendererBase {
     public:
         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
@@ -890,7 +890,7 @@
     EXPECT_EQ(5, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayer_nested) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_nested) {
     /* saveLayer1 { rect1, saveLayer2 { rect2 } } will play back as:
      * - startTemporaryLayer2, rect2 endLayer2
      * - startTemporaryLayer1, rect1, drawLayer2, endLayer1
@@ -973,7 +973,7 @@
     EXPECT_EQ(12, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayer_contentRejection) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayer_contentRejection) {
         auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
                 [](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
@@ -996,7 +996,7 @@
     frameBuilder.replayBakedOps<TestDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_simple) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_simple) {
     class SaveLayerUnclippedSimpleTestRenderer : public TestRendererBase {
     public:
         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -1041,7 +1041,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_round) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_round) {
     class SaveLayerUnclippedRoundTestRenderer : public TestRendererBase {
     public:
         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -1075,7 +1075,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_mergedClears) {
     class SaveLayerUnclippedMergedClearsTestRenderer : public TestRendererBase {
     public:
         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -1133,7 +1133,7 @@
             << "Expect 4 copyTos, 4 copyFroms, 1 clear SimpleRects, and 1 rect.";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_clearClip) {
     class SaveLayerUnclippedClearClipTestRenderer : public TestRendererBase {
     public:
         void onCopyToLayerOp(const CopyToLayerOp& op, const BakedOpState& state) override {
@@ -1175,7 +1175,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_reject) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_reject) {
     auto node = TestUtils::createNode<RecordingCanvas>(0, 0, 200, 200,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         // unclipped savelayer + rect both in area that won't intersect with dirty
@@ -1197,7 +1197,7 @@
  * - startTemporaryLayer, onCopyToLayer, onSimpleRects, onRect, onCopyFromLayer, endLayer
  * - startFrame, onCopyToLayer, onSimpleRects, drawLayer, onCopyFromLayer, endframe
  */
-RENDERTHREAD_TEST(FrameBuilder, saveLayerUnclipped_complex) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, saveLayerUnclipped_complex) {
     class SaveLayerUnclippedComplexTestRenderer : public TestRendererBase {
     public:
         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) {
@@ -1262,7 +1262,7 @@
     EXPECT_EQ(13, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, hwLayer_simple) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_simple) {
     class HwLayerSimpleTestRenderer : public TestRendererBase {
     public:
         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
@@ -1326,7 +1326,7 @@
     *layerHandle = nullptr;
 }
 
-RENDERTHREAD_TEST(FrameBuilder, hwLayer_complex) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, hwLayer_complex) {
     /* parentLayer { greyRect, saveLayer { childLayer { whiteRect } } } will play back as:
      * - startRepaintLayer(child), rect(grey), endLayer
      * - startTemporaryLayer, drawLayer(child), endLayer
@@ -1435,7 +1435,7 @@
 }
 
 
-RENDERTHREAD_TEST(FrameBuilder, buildLayer) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, buildLayer) {
     class BuildLayerTestRenderer : public TestRendererBase {
     public:
         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
@@ -1531,7 +1531,7 @@
 
 } // end anonymous namespace
 
-RENDERTHREAD_TEST(FrameBuilder, zReorder) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, zReorder) {
     auto parent = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         canvas.insertReorderBarrier(true);
@@ -1566,7 +1566,7 @@
     EXPECT_EQ(13, renderer.getIndex());
 };
 
-RENDERTHREAD_TEST(FrameBuilder, projectionReorder) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorder) {
     static const int scrollX = 5;
     static const int scrollY = 10;
     class ProjectionReorderTestRenderer : public TestRendererBase {
@@ -1659,7 +1659,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionHwLayer) {
     static const int scrollX = 5;
     static const int scrollY = 10;
     class ProjectionHwLayerTestRenderer : public TestRendererBase {
@@ -1750,7 +1750,7 @@
     *layerHandle = nullptr;
 }
 
-RENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, projectionChildScroll) {
     static const int scrollX = 500000;
     static const int scrollY = 0;
     class ProjectionChildScrollTestRenderer : public TestRendererBase {
@@ -1817,7 +1817,7 @@
     });
 }
 
-RENDERTHREAD_TEST(FrameBuilder, shadow) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadow) {
     class ShadowTestRenderer : public TestRendererBase {
     public:
         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
@@ -1850,7 +1850,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, shadowSaveLayer) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowSaveLayer) {
     class ShadowSaveLayerTestRenderer : public TestRendererBase {
     public:
         OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height) override {
@@ -1896,7 +1896,7 @@
     EXPECT_EQ(6, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, shadowHwLayer) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowHwLayer) {
     class ShadowHwLayerTestRenderer : public TestRendererBase {
     public:
         void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
@@ -1954,7 +1954,7 @@
     *layerHandle = nullptr;
 }
 
-RENDERTHREAD_TEST(FrameBuilder, shadowLayering) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowLayering) {
     class ShadowLayeringTestRenderer : public TestRendererBase {
     public:
         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
@@ -1981,7 +1981,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-RENDERTHREAD_TEST(FrameBuilder, shadowClipping) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, shadowClipping) {
     class ShadowClippingTestRenderer : public TestRendererBase {
     public:
         void onShadowOp(const ShadowOp& op, const BakedOpState& state) override {
@@ -2041,7 +2041,7 @@
     EXPECT_EQ(1, renderer.getIndex()) << "Should have seen one op";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOverlappingRenderingAlpha) {
     testProperty([](RenderProperties& properties) {
         properties.setAlpha(0.5f);
         properties.setHasOverlappingRendering(false);
@@ -2050,7 +2050,7 @@
     });
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropClipping) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropClipping) {
     testProperty([](RenderProperties& properties) {
         properties.setClipToBounds(true);
         properties.setClipBounds(Rect(10, 20, 300, 400));
@@ -2060,7 +2060,7 @@
     });
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropRevealClip) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropRevealClip) {
     testProperty([](RenderProperties& properties) {
         properties.mutableRevealClip().set(true, 50, 50, 25);
     }, [](const RectOp& op, const BakedOpState& state) {
@@ -2071,7 +2071,7 @@
     });
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropOutlineClip) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropOutlineClip) {
     testProperty([](RenderProperties& properties) {
         properties.mutableOutline().setShouldClip(true);
         properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
@@ -2083,7 +2083,7 @@
     });
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropTransform) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropTransform) {
     testProperty([](RenderProperties& properties) {
         properties.setLeftTopRightBottom(10, 10, 110, 110);
 
@@ -2192,7 +2192,7 @@
     ASSERT_EQ(5, renderer.getIndex()) << "Test must trigger saveLayer alpha behavior.";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaClipBig) {
     SaveLayerAlphaData observedData;
     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
         properties.setTranslationX(10); // offset rendering content
@@ -2211,7 +2211,7 @@
                 << "expect drawLayer to be translated as part of being clipped";
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaRotate) {
     SaveLayerAlphaData observedData;
     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
         // Translate and rotate the view so that the only visible part is the top left corner of
@@ -2230,7 +2230,7 @@
     EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, renderPropSaveLayerAlphaScale) {
     SaveLayerAlphaData observedData;
     testSaveLayerAlphaClip(&observedData, [](RenderProperties& properties) {
         properties.setPivotX(0);
@@ -2244,7 +2244,7 @@
     EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), observedData.rectMatrix);
 }
 
-RENDERTHREAD_TEST(FrameBuilder, clip_replace) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(FrameBuilder, clip_replace) {
     class ClipReplaceTestRenderer : public TestRendererBase {
     public:
         void onColorOp(const ColorOp& op, const BakedOpState& state) override {
@@ -2269,7 +2269,7 @@
     EXPECT_EQ(1, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderProjectedInMiddle) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectedInMiddle) {
     /* R is backward projected on B
                 A
                / \
@@ -2299,7 +2299,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderProjectLast) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderProjectLast) {
     /* R is backward projected on E
                   A
                 / | \
@@ -2331,7 +2331,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderNoReceivable) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderNoReceivable) {
     /* R is backward projected without receiver
                 A
                / \
@@ -2360,7 +2360,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderParentReceivable) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderParentReceivable) {
     /* R is backward projected on C
                 A
                / \
@@ -2389,7 +2389,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderSameNodeReceivable) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderSameNodeReceivable) {
      auto nodeA = TestUtils::createNode<RecordingCanvas>(0, 0, 100, 100,
             [](RenderProperties& props, RecordingCanvas& canvas) {
         drawOrderedNode(&canvas, 0, nullptr); //nodeB
@@ -2412,7 +2412,7 @@
     EXPECT_EQ(2, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderProjectedSibling) {
+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
@@ -2445,7 +2445,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderProjectedSibling2) {
+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
                 |
@@ -2478,7 +2478,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderGrandparentReceivable) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderGrandparentReceivable) {
     /* R is backward projected on B
                 A
                 |
@@ -2510,7 +2510,7 @@
     EXPECT_EQ(3, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderTwoReceivables) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivables) {
     /* B and G are receivables, R is backward projected
                 A
                / \
@@ -2543,7 +2543,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderTwoReceivablesLikelyScenario) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesLikelyScenario) {
     /* B and G are receivables, G is backward projected
                 A
                / \
@@ -2576,7 +2576,7 @@
     EXPECT_EQ(4, renderer.getIndex());
 }
 
-TEST(FrameBuilder, projectionReorderTwoReceivablesDeeper) {
+OPENGL_PIPELINE_TEST(FrameBuilder, projectionReorderTwoReceivablesDeeper) {
     /* B and G are receivables, R is backward projected
                 A
                / \
diff --git a/libs/hwui/tests/unit/GlopBuilderTests.cpp b/libs/hwui/tests/unit/GlopBuilderTests.cpp
index ce1db05..caeb6bf 100644
--- a/libs/hwui/tests/unit/GlopBuilderTests.cpp
+++ b/libs/hwui/tests/unit/GlopBuilderTests.cpp
@@ -116,7 +116,7 @@
     return glop;
 }
 
-RENDERTHREAD_TEST(GlopBuilder, rectSnapTest) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(GlopBuilder, rectSnapTest) {
     RenderState& renderState = renderThread.renderState();
     Caches& caches = Caches::getInstance();
     SkPaint paint;
diff --git a/libs/hwui/tests/unit/GradientCacheTests.cpp b/libs/hwui/tests/unit/GradientCacheTests.cpp
index 0ee9647..a3b346f 100644
--- a/libs/hwui/tests/unit/GradientCacheTests.cpp
+++ b/libs/hwui/tests/unit/GradientCacheTests.cpp
@@ -23,7 +23,7 @@
 using namespace android;
 using namespace android::uirenderer;
 
-RENDERTHREAD_TEST(GradientCache, addRemove) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(GradientCache, addRemove) {
     Extensions extensions;
     GradientCache cache(extensions);
     ASSERT_LT(1000u, cache.getMaxSize()) << "Expect non-trivial size";
diff --git a/libs/hwui/tests/unit/LeakCheckTests.cpp b/libs/hwui/tests/unit/LeakCheckTests.cpp
index 06599dd..6c42ca1 100644
--- a/libs/hwui/tests/unit/LeakCheckTests.cpp
+++ b/libs/hwui/tests/unit/LeakCheckTests.cpp
@@ -29,7 +29,7 @@
 const FrameBuilder::LightGeometry sLightGeometery = { {100, 100, 100}, 50};
 const BakedOpRenderer::LightInfo sLightInfo = { 128, 128 };
 
-RENDERTHREAD_TEST(LeakCheck, saveLayer_overdrawRejection) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayer_overdrawRejection) {
     auto node = TestUtils::createNode(0, 0, 100, 100,
             [](RenderProperties& props, Canvas& canvas) {
         canvas.saveLayerAlpha(0, 0, 100, 100, 128, SaveFlags::ClipToLayer);
@@ -49,7 +49,7 @@
     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
 }
 
-RENDERTHREAD_TEST(LeakCheck, saveLayerUnclipped_simple) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(LeakCheck, saveLayerUnclipped_simple) {
     auto node = TestUtils::createNode(0, 0, 200, 200,
             [](RenderProperties& props, Canvas& canvas) {
         canvas.saveLayerAlpha(10, 10, 190, 190, 128, (SaveFlags::Flags)(0));
diff --git a/libs/hwui/tests/unit/MeshStateTests.cpp b/libs/hwui/tests/unit/MeshStateTests.cpp
index 0881fa2..511d6d2 100644
--- a/libs/hwui/tests/unit/MeshStateTests.cpp
+++ b/libs/hwui/tests/unit/MeshStateTests.cpp
@@ -24,7 +24,7 @@
 using namespace android::uirenderer;
 using namespace testing;
 
-RENDERTHREAD_TEST(MeshState, genOrUpdate) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(MeshState, genOrUpdate) {
     debug::ScopedReplaceDriver<debug::MockGlesDriver> driverRef;
     auto& mockGlDriver = driverRef.get();
     EXPECT_CALL(mockGlDriver, glGenBuffers_(_, _)).WillOnce(SetArgPointee<1>(35));
@@ -33,4 +33,4 @@
 
     GLuint buffer = 0;
     renderThread.renderState().meshState().genOrUpdateMeshBuffer(&buffer, 10, nullptr, GL_DYNAMIC_DRAW);
-}
\ No newline at end of file
+}
diff --git a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
index b7950aa..6cd595a 100644
--- a/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
+++ b/libs/hwui/tests/unit/OffscreenBufferPoolTests.cpp
@@ -30,7 +30,7 @@
     EXPECT_EQ(1024u, OffscreenBuffer::computeIdealDimension(1000));
 }
 
-RENDERTHREAD_TEST(OffscreenBuffer, construct) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, construct) {
     OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 49u, 149u);
     EXPECT_EQ(49u, layer.viewportWidth);
     EXPECT_EQ(149u, layer.viewportHeight);
@@ -41,7 +41,7 @@
     EXPECT_EQ(64u * 192u * 4u, layer.getSizeInBytes());
 }
 
-RENDERTHREAD_TEST(OffscreenBuffer, getTextureCoordinates) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, getTextureCoordinates) {
     OffscreenBuffer layerAligned(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
     EXPECT_EQ(Rect(0, 1, 1, 0),
             layerAligned.getTextureCoordinates());
@@ -51,7 +51,7 @@
             layerUnaligned.getTextureCoordinates());
 }
 
-RENDERTHREAD_TEST(OffscreenBuffer, dirty) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBuffer, dirty) {
     OffscreenBuffer buffer(renderThread.renderState(), Caches::getInstance(), 256u, 256u);
     buffer.dirty(Rect(-100, -100, 100, 100));
     EXPECT_EQ(android::Rect(100, 100), buffer.region.getBounds());
@@ -65,7 +65,7 @@
             << "pool must read size from Properties";
 }
 
-RENDERTHREAD_TEST(OffscreenBufferPool, getPutClear) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, getPutClear) {
     OffscreenBufferPool pool;
 
     auto layer = pool.get(renderThread.renderState(), 100u, 200u);
@@ -88,7 +88,7 @@
     EXPECT_EQ(0u, pool.getCount());
 }
 
-RENDERTHREAD_TEST(OffscreenBufferPool, resize) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, resize) {
     OffscreenBufferPool pool;
 
     auto layer = pool.get(renderThread.renderState(), 64u, 64u);
@@ -123,7 +123,7 @@
     pool.putOrDelete(layer2);
 }
 
-RENDERTHREAD_TEST(OffscreenBufferPool, putAndDestroy) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, putAndDestroy) {
     OffscreenBufferPool pool;
     // layer too big to return to the pool
     // Note: this relies on the fact that the pool won't reject based on max texture size
@@ -133,7 +133,7 @@
     EXPECT_EQ(0u, pool.getCount()); // failed to put (so was destroyed instead)
 }
 
-RENDERTHREAD_TEST(OffscreenBufferPool, clear) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(OffscreenBufferPool, clear) {
     EXPECT_EQ(0, GpuMemoryTracker::getInstanceCount(GpuObjectType::OffscreenBuffer));
     OffscreenBufferPool pool;
 
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 4a73383..124f5fa 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -47,7 +47,13 @@
     opValidator(*(dl->getOps()[0]));
 }
 
-TEST(RecordingCanvas, emptyPlayback) {
+// The RecordingCanvas is only ever used by the OpenGL RenderPipeline and never when Skia is in use.
+// Thus, even though many of these test are not directly dependent on the current RenderPipeline, we
+// set them all to be OPENGL_PIPELINE_TESTs in case the underlying code in RecordingCanvas ever
+// changes to require the use of the OPENGL_PIPELINE. Currently the textureLayer test is the only
+// test that requires being an OPENGL_PIPELINE_TEST.
+
+OPENGL_PIPELINE_TEST(RecordingCanvas, emptyPlayback) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.restore();
@@ -55,7 +61,7 @@
     playbackOps(*dl, [](const RecordedOp& op) { ADD_FAILURE(); });
 }
 
-TEST(RecordingCanvas, clipRect) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, clipRect) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
@@ -71,7 +77,7 @@
             << "Clip should be serialized once";
 }
 
-TEST(RecordingCanvas, emptyClipRect) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, emptyClipRect) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.clipRect(0, 0, 100, 100, SkClipOp::kIntersect);
@@ -82,7 +88,7 @@
     ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected.";
 }
 
-TEST(RecordingCanvas, emptyPaintRejection) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, emptyPaintRejection) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint emptyPaint;
         emptyPaint.setColor(Color::Transparent);
@@ -103,7 +109,7 @@
     EXPECT_EQ(0u, dl->getOps().size()) << "Op should be rejected";
 }
 
-TEST(RecordingCanvas, drawArc) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawArc) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint());
         canvas.drawArc(0, 0, 100, 100, 0, 360, true, SkPaint());
@@ -119,7 +125,7 @@
     EXPECT_EQ(Rect(100, 100), ops[1]->unmappedBounds);
 }
 
-TEST(RecordingCanvas, drawLines) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawLines) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setStrokeWidth(20); // doesn't affect recorded bounds - would be resolved at bake time
@@ -136,7 +142,7 @@
             << "unmapped bounds must be size of line, and not outset for stroke width";
 }
 
-TEST(RecordingCanvas, drawRect) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawRect) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         canvas.drawRect(10, 20, 90, 180, SkPaint());
     });
@@ -148,7 +154,7 @@
     EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
 }
 
-TEST(RecordingCanvas, drawRoundRect) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawRoundRect) {
     // Round case - stays rounded
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         canvas.drawRoundRect(0, 0, 100, 100, 10, 10, SkPaint());
@@ -165,7 +171,7 @@
         << "Non-rounded rects should be converted";
 }
 
-TEST(RecordingCanvas, drawGlyphs) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
@@ -186,7 +192,7 @@
     ASSERT_EQ(1, count);
 }
 
-TEST(RecordingCanvas, drawGlyphs_strikeThruAndUnderline) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_strikeThruAndUnderline) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
@@ -218,7 +224,7 @@
     EXPECT_EQ(RecordedOpId::RectOp, ops[index++]->opId); // strikethrough
 }
 
-TEST(RecordingCanvas, drawGlyphs_forceAlignLeft) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawGlyphs_forceAlignLeft) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
         paint.setAntiAlias(true);
@@ -248,7 +254,7 @@
     ASSERT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, drawColor) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawColor) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.drawColor(Color::Black, SkBlendMode::kSrcOver);
     });
@@ -260,7 +266,7 @@
     EXPECT_TRUE(op.unmappedBounds.isEmpty()) << "Expect undefined recorded bounds";
 }
 
-TEST(RecordingCanvas, backgroundAndImage) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, backgroundAndImage) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         sk_sp<Bitmap> bitmap(TestUtils::createBitmap(25, 25));
         SkPaint paint;
@@ -312,7 +318,7 @@
     ASSERT_EQ(2, count);
 }
 
-RENDERTHREAD_TEST(RecordingCanvas, textureLayer) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(RecordingCanvas, textureLayer) {
     auto layerUpdater = TestUtils::createTextureLayerUpdater(renderThread, 100, 100,
             SkMatrix::MakeTrans(5, 5));
 
@@ -327,7 +333,7 @@
     });
 }
 
-TEST(RecordingCanvas, saveLayer_simple) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_simple) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.saveLayerAlpha(10, 20, 190, 180, 128, SaveFlags::ClipToLayer);
         canvas.drawRect(10, 20, 190, 180, SkPaint());
@@ -361,7 +367,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_rounding) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rounding) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
             canvas.saveLayerAlpha(10.25f, 10.75f, 89.25f, 89.75f, 128, SaveFlags::ClipToLayer);
             canvas.drawRect(20, 20, 80, 80, SkPaint());
@@ -391,7 +397,7 @@
         EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_missingRestore) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_missingRestore) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.saveLayerAlpha(0, 0, 200, 200, 128, SaveFlags::ClipToLayer);
         canvas.drawRect(0, 0, 200, 200, SkPaint());
@@ -406,7 +412,7 @@
     EXPECT_EQ(3, count) << "Missing a restore shouldn't result in an unmatched saveLayer";
 }
 
-TEST(RecordingCanvas, saveLayer_simpleUnclipped) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_simpleUnclipped) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.saveLayerAlpha(10, 20, 190, 180, 128, (SaveFlags::Flags)0); // unclipped
         canvas.drawRect(10, 20, 190, 180, SkPaint());
@@ -438,7 +444,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_addClipFlag) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_addClipFlag) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.clipRect(10, 20, 190, 180, SkClipOp::kIntersect);
@@ -457,7 +463,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_viewportCrop) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_viewportCrop) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         // shouldn't matter, since saveLayer will clip to its bounds
         canvas.clipRect(-1000, -1000, 1000, 1000, SkClipOp::kReplace);
@@ -481,7 +487,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_rotateUnclipped) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rotateUnclipped) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.translate(100, 100);
@@ -507,7 +513,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_rotateClipped) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rotateClipped) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.translate(100, 100);
@@ -545,7 +551,7 @@
     EXPECT_EQ(3, count);
 }
 
-TEST(RecordingCanvas, saveLayer_rejectBegin) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, saveLayer_rejectBegin) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.translate(0, -20); // avoid identity case
@@ -560,7 +566,7 @@
     ASSERT_EQ(0u, dl->getOps().size()) << "Begin/Rect/End should all be rejected.";
 }
 
-TEST(RecordingCanvas, drawRenderNode_rejection) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_rejection) {
     auto child = TestUtils::createNode(50, 50, 150, 150,
             [](RenderProperties& props, Canvas& canvas) {
         SkPaint paint;
@@ -575,7 +581,7 @@
     ASSERT_TRUE(dl->isEmpty());
 }
 
-TEST(RecordingCanvas, drawRenderNode_projection) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawRenderNode_projection) {
     sp<RenderNode> background = TestUtils::createNode(50, 50, 150, 150,
             [](RenderProperties& props, Canvas& canvas) {
         SkPaint paint;
@@ -618,7 +624,7 @@
     }
 }
 
-TEST(RecordingCanvas, firstClipWillReplace) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, firstClipWillReplace) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         // since no explicit clip set on canvas, this should be the one observed on op:
@@ -635,7 +641,7 @@
     EXPECT_CLIP_RECT(Rect(-100, -100, 300, 300), dl->getOps()[0]->localClip);
 }
 
-TEST(RecordingCanvas, replaceClipIntersectWithRoot) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, replaceClipIntersectWithRoot) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
         canvas.save(SaveFlags::MatrixClip);
         canvas.clipRect(-10, -10, 110, 110, SkClipOp::kReplace);
@@ -648,7 +654,7 @@
     EXPECT_TRUE(dl->getOps()[0]->localClip->intersectWithRoot);
 }
 
-TEST(RecordingCanvas, insertReorderBarrier) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, insertReorderBarrier) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.drawRect(0, 0, 400, 400, SkPaint());
         canvas.insertReorderBarrier(true);
@@ -669,7 +675,7 @@
     EXPECT_TRUE(chunks[1].reorderChildren);
 }
 
-TEST(RecordingCanvas, insertReorderBarrier_clip) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, insertReorderBarrier_clip) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         // first chunk: no recorded clip
         canvas.insertReorderBarrier(true);
@@ -699,7 +705,7 @@
     EXPECT_EQ(Rect(200, 200), chunks[2].reorderClip->rect);
 }
 
-TEST(RecordingCanvas, refPaint) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, refPaint) {
     SkPaint paint;
 
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [&paint](RecordingCanvas& canvas) {
@@ -727,7 +733,7 @@
     EXPECT_NE(&paint, ops[2]->paint);
 }
 
-TEST(RecordingCanvas, refBitmap) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmap) {
     sk_sp<Bitmap> bitmap(TestUtils::createBitmap(100, 100));
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
         canvas.drawBitmap(*bitmap, 0, 0, nullptr);
@@ -736,7 +742,7 @@
     EXPECT_EQ(1u, bitmaps.size());
 }
 
-TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmapInShader_bitmapShader) {
     sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100);
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
         SkPaint paint;
@@ -755,7 +761,7 @@
     EXPECT_EQ(1u, bitmaps.size());
 }
 
-TEST(RecordingCanvas, refBitmapInShader_composeShader) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, refBitmapInShader_composeShader) {
     sk_sp<Bitmap> bitmap = TestUtils::createBitmap(100, 100);
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [&bitmap](RecordingCanvas& canvas) {
         SkPaint paint;
@@ -785,7 +791,7 @@
     EXPECT_EQ(1u, bitmaps.size());
 }
 
-TEST(RecordingCanvas, drawText) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawText) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         Paint paint;
         paint.setAntiAlias(true);
@@ -807,7 +813,7 @@
     ASSERT_EQ(1, count);
 }
 
-TEST(RecordingCanvas, drawTextInHighContrast) {
+OPENGL_PIPELINE_TEST(RecordingCanvas, drawTextInHighContrast) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.setHighContrastText(true);
         Paint paint;
diff --git a/libs/hwui/tests/unit/RenderNodeTests.cpp b/libs/hwui/tests/unit/RenderNodeTests.cpp
index 331a6ac..ab8e4e1 100644
--- a/libs/hwui/tests/unit/RenderNodeTests.cpp
+++ b/libs/hwui/tests/unit/RenderNodeTests.cpp
@@ -137,10 +137,11 @@
 RENDERTHREAD_TEST(RenderNode, prepareTree_HwLayer_AVD_enqueueDamage) {
 
     VectorDrawable::Group* group = new VectorDrawable::Group();
-    VectorDrawableRoot* vectorDrawable = new VectorDrawableRoot(group);
+    sp<VectorDrawableRoot> vectorDrawable(new VectorDrawableRoot(group));
+
     auto rootNode = TestUtils::createNode(0, 0, 200, 400,
             [&](RenderProperties& props, Canvas& canvas) {
-        canvas.drawVectorDrawable(vectorDrawable);
+        canvas.drawVectorDrawable(vectorDrawable.get());
     });
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
@@ -164,7 +165,5 @@
     EXPECT_FALSE(info.layerUpdateQueue->entries().empty());
     EXPECT_EQ(rootNode.get(), info.layerUpdateQueue->entries().at(0).renderNode);
     EXPECT_EQ(uirenderer::Rect(0, 0, 200, 400), info.layerUpdateQueue->entries().at(0).damage);
-
-    delete vectorDrawable;
     canvasContext->destroy(nullptr);
 }
diff --git a/libs/hwui/tests/unit/SkiaCanvasTests.cpp b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
index 95f9974..0ac09ac 100644
--- a/libs/hwui/tests/unit/SkiaCanvasTests.cpp
+++ b/libs/hwui/tests/unit/SkiaCanvasTests.cpp
@@ -28,7 +28,7 @@
  * Verify that we get the same culling bounds for text for (1) drawing glyphs
  * directly to a Canvas or (2) going through a SkPicture as an intermediate step.
  */
-TEST(SkiaCanvasProxy, drawGlyphsViaPicture) {
+OPENGL_PIPELINE_TEST(SkiaCanvasProxy, drawGlyphsViaPicture) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         // setup test variables
         SkPaint paint;
diff --git a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
index 899758a..8f6fc8b 100644
--- a/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
+++ b/libs/hwui/tests/unit/SkiaDisplayListTests.cpp
@@ -118,7 +118,7 @@
     }
 };
 
-RENDERTHREAD_TEST(SkiaDisplayList, prepareListAndChildren) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaDisplayList, prepareListAndChildren) {
     auto rootNode = TestUtils::createNode(0, 0, 200, 400, nullptr);
     ContextFactory contextFactory;
     std::unique_ptr<CanvasContext> canvasContext(CanvasContext::create(
diff --git a/libs/hwui/tests/unit/SkiaPipelineTests.cpp b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
index 494585a..0b8c2a9 100644
--- a/libs/hwui/tests/unit/SkiaPipelineTests.cpp
+++ b/libs/hwui/tests/unit/SkiaPipelineTests.cpp
@@ -36,7 +36,7 @@
 using namespace android::uirenderer::renderthread;
 using namespace android::uirenderer::skiapipeline;
 
-RENDERTHREAD_TEST(SkiaPipeline, renderFrame) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrame) {
     auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
         [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
             redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
@@ -55,7 +55,7 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 0), SK_ColorRED);
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckOpaque) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckOpaque) {
     auto halfGreenNode = TestUtils::createSkiaNode(0, 0, 2, 2,
         [](RenderProperties& props, SkiaRecordingCanvas& bottomHalfGreenCanvas) {
             SkPaint greenPaint;
@@ -80,7 +80,7 @@
     ASSERT_EQ(TestUtils::getColor(surface, 0, 1), SK_ColorGREEN);
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderFrameCheckDirtyRect) {
     auto redNode = TestUtils::createSkiaNode(0, 0, 2, 2,
         [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
             redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
@@ -101,7 +101,7 @@
     ASSERT_EQ(TestUtils::getColor(surface, 1, 1), SK_ColorRED);
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, renderLayer) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderLayer) {
     auto redNode = TestUtils::createSkiaNode(0, 0, 1, 1,
         [](RenderProperties& props, SkiaRecordingCanvas& redCanvas) {
             redCanvas.drawColor(SK_ColorRED, SkBlendMode::kSrcOver);
@@ -144,7 +144,7 @@
     blueNode->setLayerSurface(sk_sp<SkSurface>());
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, renderOverdraw) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, renderOverdraw) {
     ScopedProperty<bool> prop(Properties::debugOverdraw, true);
 
     auto whiteNode = TestUtils::createSkiaNode(0, 0, 1, 1,
@@ -218,7 +218,7 @@
 };
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, deferRenderNodeScene) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, deferRenderNodeScene) {
     class DeferTestCanvas : public SkCanvas {
     public:
         DeferTestCanvas() : SkCanvas(800, 600) {}
@@ -284,7 +284,7 @@
     EXPECT_EQ(4, surface->canvas()->mDrawCounter);
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, clipped) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clipped) {
     static const int CANVAS_WIDTH = 200;
     static const int CANVAS_HEIGHT = 200;
     class ClippedTestCanvas : public SkCanvas {
@@ -315,7 +315,7 @@
     EXPECT_EQ(1, surface->canvas()->mDrawCounter);
 }
 
-RENDERTHREAD_TEST(SkiaPipeline, clip_replace) {
+RENDERTHREAD_SKIA_PIPELINE_TEST(SkiaPipeline, clip_replace) {
     static const int CANVAS_WIDTH = 50;
     static const int CANVAS_HEIGHT = 50;
     class ClipReplaceTestCanvas : public SkCanvas {
diff --git a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
index e7171c8..92d9d3d 100644
--- a/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
+++ b/libs/hwui/tests/unit/SkiaRenderPropertiesTests.cpp
@@ -73,7 +73,7 @@
 
 }
 
-RENDERTHREAD_TEST(RenderNodeDrawable, renderPropClipping) {
+TEST(RenderNodeDrawable, renderPropClipping) {
     testProperty([](RenderProperties& properties) {
         properties.setClipToBounds(true);
         properties.setClipBounds(android::uirenderer::Rect(10, 20, 300, 400));
@@ -83,7 +83,7 @@
     });
 }
 
-RENDERTHREAD_TEST(RenderNodeDrawable, renderPropRevealClip) {
+TEST(RenderNodeDrawable, renderPropRevealClip) {
     testProperty([](RenderProperties& properties) {
         properties.mutableRevealClip().set(true, 50, 50, 25);
     }, [](const SkCanvas& canvas) {
@@ -98,7 +98,7 @@
     });
 }
 
-RENDERTHREAD_TEST(RenderNodeDrawable, renderPropOutlineClip) {
+TEST(RenderNodeDrawable, renderPropOutlineClip) {
     testProperty([](RenderProperties& properties) {
         properties.mutableOutline().setShouldClip(true);
         properties.mutableOutline().setRoundRect(10, 20, 30, 40, 5.0f, 0.5f);
@@ -114,7 +114,7 @@
     });
 }
 
-RENDERTHREAD_TEST(RenderNodeDrawable, renderPropTransform) {
+TEST(RenderNodeDrawable, renderPropTransform) {
     testProperty([](RenderProperties& properties) {
         properties.setLeftTopRightBottom(10, 10, 110, 110);
 
diff --git a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
index 0d26df2..8312bda 100644
--- a/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
+++ b/libs/hwui/tests/unit/TextDropShadowCacheTests.cpp
@@ -26,7 +26,7 @@
 using namespace android;
 using namespace android::uirenderer;
 
-RENDERTHREAD_TEST(TextDropShadowCache, addRemove) {
+RENDERTHREAD_OPENGL_PIPELINE_TEST(TextDropShadowCache, addRemove) {
     SkPaint paint;
     paint.setTextSize(20);
 
diff --git a/media/java/android/media/AudioPlaybackConfiguration.java b/media/java/android/media/AudioPlaybackConfiguration.java
index b38a07f..dd9c6a7 100644
--- a/media/java/android/media/AudioPlaybackConfiguration.java
+++ b/media/java/android/media/AudioPlaybackConfiguration.java
@@ -283,10 +283,19 @@
 
     /**
      * @hide
-     * FIXME return a player proxy instead, make systemApi
-     * @return
+     * Return a proxy for the player associated with this playback configuration
+     * @return a proxy player
      */
-    public IPlayer getPlayerProxy() {
+    @SystemApi
+    public PlayerProxy getPlayerProxy() {
+        return mIPlayerShell == null ? null : new PlayerProxy(this);
+    }
+
+    /**
+     * @hide
+     * @return the IPlayer interface for the associated player
+     */
+    IPlayer getIPlayer() {
         return mIPlayerShell == null ? null : mIPlayerShell.getIPlayer();
     }
 
diff --git a/media/java/android/media/PlayerProxy.java b/media/java/android/media/PlayerProxy.java
new file mode 100644
index 0000000..171be27
--- /dev/null
+++ b/media/java/android/media/PlayerProxy.java
@@ -0,0 +1,109 @@
+/*
+ * 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.media;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.lang.IllegalArgumentException;
+import java.util.Objects;
+
+/**
+ * Class to remotely control a player.
+ * @hide
+ */
+@SystemApi
+public class PlayerProxy {
+
+    private final static String TAG = "PlayerProxy";
+    private final static boolean DEBUG = false;
+
+    private final AudioPlaybackConfiguration mConf; // never null
+
+    /**
+     * @hide
+     * Constructor. Proxy for this player associated with this AudioPlaybackConfiguration
+     * @param conf the configuration being proxied.
+     */
+    PlayerProxy(@NonNull AudioPlaybackConfiguration apc) {
+        if (apc == null) {
+            throw new IllegalArgumentException("Illegal null AudioPlaybackConfiguration");
+        }
+        mConf = apc;
+    };
+
+    //=====================================================================
+    // Methods matching the IPlayer interface
+    /**
+     * @hide
+     * @throws IllegalStateException
+     */
+    @SystemApi
+    public void start() throws IllegalStateException {
+        try {
+            mConf.getIPlayer().start();
+        } catch (NullPointerException|RemoteException e) {
+            throw new IllegalStateException(
+                    "No player to proxy for start operation, player already released?", e);
+        }
+    }
+
+    /**
+     * @hide
+     * @throws IllegalStateException
+     */
+    @SystemApi
+    public void pause() throws IllegalStateException {
+        try {
+            mConf.getIPlayer().pause();
+        } catch (NullPointerException|RemoteException e) {
+            throw new IllegalStateException(
+                    "No player to proxy for pause operation, player already released?", e);
+        }
+    }
+
+    /**
+     * @hide
+     * @throws IllegalStateException
+     */
+    @SystemApi
+    public void stop() throws IllegalStateException {
+        try {
+            mConf.getIPlayer().stop();
+        } catch (NullPointerException|RemoteException e) {
+            throw new IllegalStateException(
+                    "No player to proxy for stop operation, player already released?", e);
+        }
+    }
+
+    /**
+     * @hide
+     * @throws IllegalStateException
+     */
+    @SystemApi
+    public void setVolume(float vol) throws IllegalStateException {
+        try {
+            mConf.getIPlayer().setVolume(vol);
+        } catch (NullPointerException|RemoteException e) {
+            throw new IllegalStateException(
+                    "No player to proxy for setVolume operation, player already released?", e);
+        }
+    }
+
+}
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 16847c1..eaec493 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -387,7 +387,6 @@
      * @see BrowserRoot#EXTRA_RECENT
      * @see BrowserRoot#EXTRA_OFFLINE
      * @see BrowserRoot#EXTRA_SUGGESTED
-     * @see BrowserRoot#EXTRA_SUGGESTION_KEYWORDS
      */
     public abstract @Nullable BrowserRoot onGetRoot(@NonNull String clientPackageName,
             int clientUid, @Nullable Bundle rootHints);
@@ -550,7 +549,6 @@
      * @see MediaBrowserService.BrowserRoot#EXTRA_RECENT
      * @see MediaBrowserService.BrowserRoot#EXTRA_OFFLINE
      * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTED
-     * @see MediaBrowserService.BrowserRoot#EXTRA_SUGGESTION_KEYWORDS
      */
     public final Bundle getBrowserRootHints() {
         if (mCurConnection == null) {
@@ -818,7 +816,6 @@
          *
          * @see #EXTRA_OFFLINE
          * @see #EXTRA_SUGGESTED
-         * @see #EXTRA_SUGGESTION_KEYWORDS
          */
         public static final String EXTRA_RECENT = "android.service.media.extra.RECENT";
 
@@ -836,7 +833,6 @@
          *
          * @see #EXTRA_RECENT
          * @see #EXTRA_SUGGESTED
-         * @see #EXTRA_SUGGESTION_KEYWORDS
          */
         public static final String EXTRA_OFFLINE = "android.service.media.extra.OFFLINE";
 
@@ -855,31 +851,9 @@
          *
          * @see #EXTRA_RECENT
          * @see #EXTRA_OFFLINE
-         * @see #EXTRA_SUGGESTION_KEYWORDS
          */
         public static final String EXTRA_SUGGESTED = "android.service.media.extra.SUGGESTED";
 
-        /**
-         * The lookup key for a string that indicates specific keywords which will be considered
-         * when the browser service suggests media items.
-         *
-         * <p>When creating a media browser for a given media browser service, this key can be
-         * supplied as a root hint together with {@link #EXTRA_SUGGESTED} for retrieving suggested
-         * media items related with the keywords. The list of media items passed in
-         * {@link android.media.browse.MediaBrowser.SubscriptionCallback#onChildrenLoaded(String, List)}
-         * is considered ordered by relevance, first being the top suggestion.
-         * If the media browser service can provide such media items, the implementation must return
-         * the key in the root hint when {@link #onGetRoot(String, int, Bundle)} is called back.
-         *
-         * <p>The root hint may contain multiple keys.
-         *
-         * @see #EXTRA_RECENT
-         * @see #EXTRA_OFFLINE
-         * @see #EXTRA_SUGGESTED
-         */
-        public static final String EXTRA_SUGGESTION_KEYWORDS
-                = "android.service.media.extra.SUGGESTION_KEYWORDS";
-
         final private String mRootId;
         final private Bundle mExtras;
 
diff --git a/media/mca/tests/Android.mk b/media/mca/tests/Android.mk
index 2abd7f6..eb451f7 100644
--- a/media/mca/tests/Android.mk
+++ b/media/mca/tests/Android.mk
@@ -5,6 +5,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
index 308c665..0d9f42b 100644
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ b/media/tests/MediaFrameworkTest/Android.mk
@@ -10,7 +10,8 @@
 LOCAL_STATIC_JAVA_LIBRARIES := \
     mockito-target-minus-junit4 \
     android-support-test \
-    android-ex-camera2
+    android-ex-camera2 \
+    legacy-android-test
 
 LOCAL_PACKAGE_NAME := mediaframeworktest
 
diff --git a/nfc-extras/Android.mk b/nfc-extras/Android.mk
index 330e2d4..cd7a45b 100644
--- a/nfc-extras/Android.mk
+++ b/nfc-extras/Android.mk
@@ -6,6 +6,8 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
+
 LOCAL_MODULE:= com.android.nfc_extras
 
 include $(BUILD_JAVA_LIBRARY)
diff --git a/packages/BackupRestoreConfirmation/res/values-it/strings.xml b/packages/BackupRestoreConfirmation/res/values-it/strings.xml
index b84edbc..1cbb770 100644
--- a/packages/BackupRestoreConfirmation/res/values-it/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-it/strings.xml
@@ -30,7 +30,7 @@
     <string name="backup_enc_password_text" msgid="4981585714795233099">"Inserisci una password da utilizzare per la crittografia dei dati di backup completi. Se non ne inserisci una, verrà utilizzata la tua password di backup corrente:"</string>
     <string name="backup_enc_password_optional" msgid="1350137345907579306">"Se desideri crittografare tutti i dati di backup, inserisci una password qui di seguito:"</string>
     <string name="backup_enc_password_required" msgid="7889652203371654149">"Il dispositivo è criptato, quindi devi criptare il backup. Inserisci una password di seguito:"</string>
-    <string name="restore_enc_password_text" msgid="6140898525580710823">"Se i dati di ripristino sono crittografati, inserisci la password qui di seguito:"</string>
+    <string name="restore_enc_password_text" msgid="6140898525580710823">"Se i dati di ripristino sono criptati, inserisci la password qui di seguito:"</string>
     <string name="toast_backup_started" msgid="550354281452756121">"Avvio del backup..."</string>
     <string name="toast_backup_ended" msgid="3818080769548726424">"Backup terminato"</string>
     <string name="toast_restore_started" msgid="7881679218971277385">"Avvio del ripristino..."</string>
diff --git a/packages/CarrierDefaultApp/tests/unit/Android.mk b/packages/CarrierDefaultApp/tests/unit/Android.mk
index 092df50..63bd0b1 100644
--- a/packages/CarrierDefaultApp/tests/unit/Android.mk
+++ b/packages/CarrierDefaultApp/tests/unit/Android.mk
@@ -21,7 +21,7 @@
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test mockito-target-minus-junit4 legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
index e1657c7..f8f4f2a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardStatusView.java
@@ -29,6 +29,7 @@
 import android.util.Slog;
 import android.util.TypedValue;
 import android.view.View;
+import android.view.ViewGroup;
 import android.widget.GridLayout;
 import android.widget.TextClock;
 import android.widget.TextView;
@@ -48,6 +49,7 @@
     private TextClock mDateView;
     private TextClock mClockView;
     private TextView mOwnerInfo;
+    private ViewGroup mClockContainer;
 
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
 
@@ -105,6 +107,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+        mClockContainer = (ViewGroup) findViewById(R.id.keyguard_clock_container);
         mAlarmStatusView = (TextView) findViewById(R.id.alarm_status);
         mDateView = (TextClock) findViewById(R.id.date_view);
         mClockView = (TextClock) findViewById(R.id.clock_view);
@@ -167,6 +170,11 @@
         }
     }
 
+    public int getClockBottom() {
+        return mClockView.getBottom() +
+                ((MarginLayoutParams) mClockView.getLayoutParams()).bottomMargin;
+    }
+
     public static String formatNextAlarm(Context context, AlarmManager.AlarmClockInfo info) {
         if (info == null) {
             return "";
@@ -260,4 +268,15 @@
             cacheKey = key;
         }
     }
+
+    public void setDark(boolean dark) {
+        final int N = mClockContainer.getChildCount();
+        for (int i = 0; i < N; i++) {
+            View child = mClockContainer.getChildAt(i);
+            if (child == mClockView) {
+                continue;
+            }
+            child.setAlpha(dark ? 0 : 1);
+        }
+    }
 }
diff --git a/packages/MtpDocumentsProvider/Android.mk b/packages/MtpDocumentsProvider/Android.mk
index c9e7195..a9e9b2e 100644
--- a/packages/MtpDocumentsProvider/Android.mk
+++ b/packages/MtpDocumentsProvider/Android.mk
@@ -6,7 +6,6 @@
 LOCAL_PACKAGE_NAME := MtpDocumentsProvider
 LOCAL_CERTIFICATE := media
 LOCAL_PRIVILEGED_MODULE := true
-LOCAL_JNI_SHARED_LIBRARIES := libappfuse_jni
 LOCAL_PROGUARD_FLAG_FILES := proguard.flags
 
 # Only enable asserts on userdebug/eng builds
diff --git a/packages/MtpDocumentsProvider/jni/Android.mk b/packages/MtpDocumentsProvider/jni/Android.mk
deleted file mode 100644
index d545b14..0000000
--- a/packages/MtpDocumentsProvider/jni/Android.mk
+++ /dev/null
@@ -1,15 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := \
-    com_android_mtp_AppFuse.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libandroid_runtime \
-    libnativehelper \
-    liblog
-
-LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
-LOCAL_MODULE := libappfuse_jni
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp b/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
deleted file mode 100644
index e948cf7..0000000
--- a/packages/MtpDocumentsProvider/jni/com_android_mtp_AppFuse.cpp
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- * Copyright (C) 2015 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 specic language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "AppFuseJNI"
-#include "utils/Log.h"
-
-#include <assert.h>
-#include <dirent.h>
-#include <inttypes.h>
-
-#include <linux/fuse.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-
-#include <map>
-
-#include "jni.h"
-#include "JNIHelp.h"
-#include "android_runtime/AndroidRuntime.h"
-#include "nativehelper/ScopedPrimitiveArray.h"
-#include "nativehelper/ScopedLocalRef.h"
-
-namespace {
-
-// The numbers came from sdcard.c.
-// Maximum number of bytes to write/read in one request/one reply.
-constexpr size_t MAX_WRITE = 256 * 1024;
-constexpr size_t MAX_READ = 128 * 1024;
-
-constexpr size_t NUM_MAX_HANDLES = 1024;
-
-// Largest possible request.
-// The request size is bounded by the maximum size of a FUSE_WRITE request
-// because it has the largest possible data payload.
-constexpr size_t MAX_REQUEST_SIZE = sizeof(struct fuse_in_header) +
-        sizeof(struct fuse_write_in) + (MAX_WRITE > MAX_READ ? MAX_WRITE : MAX_READ);
-
-static jclass app_fuse_class;
-static jmethodID app_fuse_get_file_size;
-static jmethodID app_fuse_read_object_bytes;
-static jmethodID app_fuse_write_object_bytes;
-static jmethodID app_fuse_flush_file_handle;
-static jmethodID app_fuse_close_file_handle;
-static jfieldID app_fuse_buffer;
-
-// NOTE:
-// FuseRequest and FuseResponse shares the same buffer to save memory usage, so the handlers must
-// not access input buffer after writing data to output buffer.
-struct FuseRequest {
-    char buffer[MAX_REQUEST_SIZE];
-    FuseRequest() {}
-    const struct fuse_in_header& header() const {
-        return *(const struct fuse_in_header*) buffer;
-    }
-    void* data() {
-        return (buffer + sizeof(struct fuse_in_header));
-    }
-    size_t data_length() const {
-        return header().len - sizeof(struct fuse_in_header);
-    }
-};
-
-template<typename T>
-class FuseResponse {
-   size_t size_;
-   T* const buffer_;
-public:
-   explicit FuseResponse(void* buffer) : size_(0), buffer_(static_cast<T*>(buffer)) {}
-
-   void prepare_buffer(size_t size = sizeof(T)) {
-       memset(buffer_, 0, size);
-       size_ = size;
-   }
-
-   void set_size(size_t size) {
-       size_ = size;
-   }
-
-   size_t size() const { return size_; }
-   T* data() const { return buffer_; }
-};
-
-class ScopedFd {
-    int mFd;
-
-public:
-    explicit ScopedFd(int fd) : mFd(fd) {}
-    ~ScopedFd() {
-        close(mFd);
-    }
-    operator int() {
-        return mFd;
-    }
-};
-
-/**
- * Fuse implementation consists of handlers parsing FUSE commands.
- */
-class AppFuse {
-    JNIEnv* env_;
-    jobject self_;
-
-    // Map between file handle and inode.
-    std::map<uint32_t, uint64_t> handles_;
-    uint32_t handle_counter_;
-
-public:
-    AppFuse(JNIEnv* env, jobject self) :
-        env_(env), self_(self), handle_counter_(0) {}
-
-    void handle_fuse_request(int fd, FuseRequest* req) {
-        ALOGV("Request op=%d", req->header().opcode);
-        switch (req->header().opcode) {
-            // TODO: Handle more operations that are enough to provide seekable
-            // FD.
-            case FUSE_LOOKUP:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_lookup);
-                return;
-            case FUSE_FORGET:
-                // Return without replying.
-                return;
-            case FUSE_INIT:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_init);
-                return;
-            case FUSE_GETATTR:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_getattr);
-                return;
-            case FUSE_OPEN:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_open);
-                return;
-            case FUSE_READ:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_read);
-                return;
-            case FUSE_WRITE:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_write);
-                return;
-            case FUSE_RELEASE:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_release);
-                return;
-            case FUSE_FLUSH:
-                invoke_handler(fd, req, &AppFuse::handle_fuse_flush);
-                return;
-            default: {
-                ALOGV("NOTIMPL op=%d uniq=%" PRIx64 " nid=%" PRIx64 "\n",
-                      req->header().opcode,
-                      req->header().unique,
-                      req->header().nodeid);
-                fuse_reply(fd, req->header().unique, -ENOSYS, NULL, 0);
-                return;
-            }
-        }
-    }
-
-private:
-    int handle_fuse_lookup(const fuse_in_header& header,
-                           const char* name,
-                           FuseResponse<fuse_entry_out>* out) {
-        if (header.nodeid != 1) {
-            return -ENOENT;
-        }
-
-        const int n = atoi(name);
-        if (n == 0) {
-            return -ENOENT;
-        }
-
-        int64_t size = get_file_size(n);
-        if (size < 0) {
-            return -ENOENT;
-        }
-
-        out->prepare_buffer();
-        out->data()->nodeid = n;
-        out->data()->attr_valid = 10;
-        out->data()->entry_valid = 10;
-        out->data()->attr.ino = n;
-        out->data()->attr.mode = S_IFREG | 0777;
-        out->data()->attr.size = size;
-        return 0;
-    }
-
-    int handle_fuse_init(const fuse_in_header&,
-                         const fuse_init_in* in,
-                         FuseResponse<fuse_init_out>* out) {
-        // Kernel 2.6.16 is the first stable kernel with struct fuse_init_out
-        // defined (fuse version 7.6). The structure is the same from 7.6 through
-        // 7.22. Beginning with 7.23, the structure increased in size and added
-        // new parameters.
-        if (in->major != FUSE_KERNEL_VERSION || in->minor < 6) {
-            ALOGE("Fuse kernel version mismatch: Kernel version %d.%d, "
-                  "Expected at least %d.6",
-                  in->major, in->minor, FUSE_KERNEL_VERSION);
-            return -1;
-        }
-
-        // Before writing |out|, we need to copy data from |in|.
-        const uint32_t minor = in->minor;
-        const uint32_t max_readahead = in->max_readahead;
-
-        // We limit ourselves to 15 because we don't handle BATCH_FORGET yet
-        size_t response_size = sizeof(fuse_init_out);
-#if defined(FUSE_COMPAT_22_INIT_OUT_SIZE)
-        // FUSE_KERNEL_VERSION >= 23.
-
-        // If the kernel only works on minor revs older than or equal to 22,
-        // then use the older structure size since this code only uses the 7.22
-        // version of the structure.
-        if (minor <= 22) {
-            response_size = FUSE_COMPAT_22_INIT_OUT_SIZE;
-        }
-#endif
-        out->prepare_buffer(response_size);
-        out->data()->major = FUSE_KERNEL_VERSION;
-        out->data()->minor = std::min(minor, 15u);
-        out->data()->max_readahead = max_readahead;
-        out->data()->flags = FUSE_ATOMIC_O_TRUNC | FUSE_BIG_WRITES;
-        out->data()->max_background = 32;
-        out->data()->congestion_threshold = 32;
-        out->data()->max_write = MAX_WRITE;
-
-        return 0;
-    }
-
-    int handle_fuse_getattr(const fuse_in_header& header,
-                            const fuse_getattr_in* /* in */,
-                            FuseResponse<fuse_attr_out>* out) {
-        out->prepare_buffer();
-        out->data()->attr_valid = 10;
-        out->data()->attr.ino = header.nodeid;
-        if (header.nodeid == 1) {
-            out->data()->attr.mode = S_IFDIR | 0777;
-            out->data()->attr.size = 0;
-        } else {
-            int64_t size = get_file_size(header.nodeid);
-            if (size < 0) {
-                return -ENOENT;
-            }
-            out->data()->attr.mode = S_IFREG | 0777;
-            out->data()->attr.size = size;
-        }
-
-        return 0;
-    }
-
-    int handle_fuse_open(const fuse_in_header& header,
-                         const fuse_open_in* /* in */,
-                         FuseResponse<fuse_open_out>* out) {
-        if (handles_.size() >= NUM_MAX_HANDLES) {
-            // Too many open files.
-            return -EMFILE;
-        }
-        uint32_t handle;
-        do {
-           handle = handle_counter_++;
-        } while (handles_.count(handle) != 0);
-        handles_.insert(std::make_pair(handle, header.nodeid));
-
-        out->prepare_buffer();
-        out->data()->fh = handle;
-        return 0;
-    }
-
-    int handle_fuse_read(const fuse_in_header& /* header */,
-                         const fuse_read_in* in,
-                         FuseResponse<void>* out) {
-        if (in->size > MAX_READ) {
-            return -EINVAL;
-        }
-        const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
-        if (it == handles_.end()) {
-            return -EBADF;
-        }
-        uint64_t offset = in->offset;
-        uint32_t size = in->size;
-
-        // Overwrite the size after writing data.
-        out->prepare_buffer(0);
-        const int64_t result = get_object_bytes(it->second, offset, size, out->data());
-        if (result < 0) {
-            return result;
-        }
-        out->set_size(result);
-        return 0;
-    }
-
-    int handle_fuse_write(const fuse_in_header& /* header */,
-                          const fuse_write_in* in,
-                          FuseResponse<fuse_write_out>* out) {
-        if (in->size > MAX_WRITE) {
-            return -EINVAL;
-        }
-        const std::map<uint32_t, uint64_t>::iterator it = handles_.find(in->fh);
-        if (it == handles_.end()) {
-            return -EBADF;
-        }
-        const uint64_t offset = in->offset;
-        const uint32_t size = in->size;
-        const void* const buffer = reinterpret_cast<const uint8_t*>(in) + sizeof(fuse_write_in);
-        uint32_t written_size;
-        const int result = write_object_bytes(
-                in->fh, it->second, offset, size, buffer, &written_size);
-        if (result < 0) {
-            return result;
-        }
-        out->prepare_buffer();
-        out->data()->size = written_size;
-        return 0;
-    }
-
-    int handle_fuse_release(const fuse_in_header& /* header */,
-                            const fuse_release_in* in,
-                            FuseResponse<void>* /* out */) {
-        handles_.erase(in->fh);
-        return env_->CallIntMethod(self_, app_fuse_close_file_handle, file_handle_to_jlong(in->fh));
-    }
-
-    int handle_fuse_flush(const fuse_in_header& /* header */,
-                          const fuse_flush_in* in,
-                          FuseResponse<void>* /* out */) {
-        return env_->CallIntMethod(self_, app_fuse_flush_file_handle, file_handle_to_jlong(in->fh));
-    }
-
-    template <typename T, typename S>
-    void invoke_handler(int fd,
-                        FuseRequest* request,
-                        int (AppFuse::*handler)(const fuse_in_header&,
-                                                const T*,
-                                                FuseResponse<S>*)) {
-        FuseResponse<S> response(request->data());
-        const int reply_code = (this->*handler)(
-                request->header(),
-                static_cast<const T*>(request->data()),
-                &response);
-        fuse_reply(
-                fd,
-                request->header().unique,
-                reply_code,
-                request->data(),
-                response.size());
-    }
-
-    int64_t get_file_size(int inode) {
-        return static_cast<int64_t>(env_->CallLongMethod(
-                self_,
-                app_fuse_get_file_size,
-                static_cast<int>(inode)));
-    }
-
-    int64_t get_object_bytes(
-            int inode,
-            uint64_t offset,
-            uint32_t size,
-            void* buf) {
-        const jlong read_size = env_->CallLongMethod(
-                self_,
-                app_fuse_read_object_bytes,
-                static_cast<jint>(inode),
-                static_cast<jlong>(offset),
-                static_cast<jlong>(size));
-        if (read_size <= 0) {
-            return read_size;
-        }
-        ScopedLocalRef<jbyteArray> array(
-                env_, static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
-        if (array.get() == nullptr) {
-            return -EFAULT;
-        }
-        ScopedByteArrayRO bytes(env_, array.get());
-        if (bytes.get() == nullptr) {
-            return -ENOMEM;
-        }
-        memcpy(buf, bytes.get(), read_size);
-        return read_size;
-    }
-
-    int write_object_bytes(uint64_t handle, int inode, uint64_t offset, uint32_t size,
-                           const void* buffer, uint32_t* written_size) {
-        static_assert(sizeof(uint64_t) <= sizeof(jlong),
-                      "jlong must be able to express any uint64_t values");
-        ScopedLocalRef<jbyteArray> array(
-                env_,
-                static_cast<jbyteArray>(env_->GetObjectField(self_, app_fuse_buffer)));
-        {
-            ScopedByteArrayRW bytes(env_, array.get());
-            if (bytes.get() == nullptr) {
-                return -EIO;
-            }
-            memcpy(bytes.get(), buffer, size);
-        }
-        const int result = env_->CallIntMethod(
-                self_,
-                app_fuse_write_object_bytes,
-                file_handle_to_jlong(handle),
-                inode,
-                offset,
-                size,
-                array.get());
-        if (result < 0) {
-            return result;
-        }
-        *written_size = result;
-        return 0;
-    }
-
-    static jlong file_handle_to_jlong(uint64_t handle) {
-        static_assert(
-                sizeof(uint64_t) <= sizeof(jlong),
-                "jlong must be able to express any uint64_t values");
-        return static_cast<jlong>(handle);
-    }
-
-    static void fuse_reply(int fd, int unique, int reply_code, void* reply_data,
-                           size_t reply_size) {
-        // Don't send any data for error case.
-        if (reply_code != 0) {
-            reply_size = 0;
-        }
-
-        struct fuse_out_header hdr;
-        hdr.len = reply_size + sizeof(hdr);
-        hdr.error = reply_code;
-        hdr.unique = unique;
-
-        struct iovec vec[2];
-        vec[0].iov_base = &hdr;
-        vec[0].iov_len = sizeof(hdr);
-        vec[1].iov_base = reply_data;
-        vec[1].iov_len = reply_size;
-
-        const int res = writev(fd, vec, reply_size != 0 ? 2 : 1);
-        if (res < 0) {
-            ALOGE("*** REPLY FAILED *** %d\n", errno);
-        }
-    }
-};
-
-void com_android_mtp_AppFuse_start_app_fuse_loop(JNIEnv* env, jobject self, jint jfd) {
-    ScopedFd fd(static_cast<int>(jfd));
-    AppFuse appfuse(env, self);
-
-    ALOGV("Start fuse loop.");
-    while (true) {
-        FuseRequest request;
-
-        const ssize_t result = TEMP_FAILURE_RETRY(
-                read(fd, request.buffer, sizeof(request.buffer)));
-        if (result < 0) {
-            if (errno == ENODEV) {
-                ALOGV("AppFuse was unmounted.\n");
-                return;
-            }
-            ALOGE("Failed to read bytes from FD: errno=%d\n", errno);
-            continue;
-        }
-
-        const size_t length = static_cast<size_t>(result);
-        if (length < sizeof(struct fuse_in_header)) {
-            ALOGE("request too short: len=%zu\n", length);
-            continue;
-        }
-
-        if (request.header().len != length) {
-            ALOGE("malformed header: len=%zu, hdr->len=%u\n",
-                  length, request.header().len);
-            continue;
-        }
-
-        appfuse.handle_fuse_request(fd, &request);
-    }
-}
-
-static const JNINativeMethod gMethods[] = {
-    {
-        "native_start_app_fuse_loop",
-        "(I)V",
-        (void *) com_android_mtp_AppFuse_start_app_fuse_loop
-    }
-};
-
-}
-
-jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) {
-    JNIEnv* env = nullptr;
-    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
-        ALOGE("ERROR: GetEnv failed\n");
-        return -1;
-
-    }
-    assert(env != nullptr);
-
-    jclass clazz = env->FindClass("com/android/mtp/AppFuse");
-    if (clazz == nullptr) {
-        ALOGE("Can't find com/android/mtp/AppFuse");
-        return -1;
-    }
-
-    app_fuse_class = static_cast<jclass>(env->NewGlobalRef(clazz));
-    if (app_fuse_class == nullptr) {
-        ALOGE("Can't obtain global reference for com/android/mtp/AppFuse");
-        return -1;
-    }
-
-    app_fuse_get_file_size = env->GetMethodID(
-            app_fuse_class, "getFileSize", "(I)J");
-    if (app_fuse_get_file_size == nullptr) {
-        ALOGE("Can't find getFileSize");
-        return -1;
-    }
-
-    app_fuse_read_object_bytes = env->GetMethodID(
-            app_fuse_class, "readObjectBytes", "(IJJ)J");
-    if (app_fuse_read_object_bytes == nullptr) {
-        ALOGE("Can't find readObjectBytes");
-        return -1;
-    }
-
-    app_fuse_write_object_bytes = env->GetMethodID(app_fuse_class, "writeObjectBytes", "(JIJI[B)I");
-    if (app_fuse_write_object_bytes == nullptr) {
-        ALOGE("Can't find writeObjectBytes");
-        return -1;
-    }
-
-    app_fuse_flush_file_handle = env->GetMethodID(app_fuse_class, "flushFileHandle", "(J)I");
-    if (app_fuse_flush_file_handle == nullptr) {
-        ALOGE("Can't find flushFileHandle");
-        return -1;
-    }
-
-    app_fuse_close_file_handle = env->GetMethodID(app_fuse_class, "closeFileHandle", "(J)I");
-    if (app_fuse_close_file_handle == nullptr) {
-        ALOGE("Can't find closeFileHandle");
-        return -1;
-    }
-
-    app_fuse_buffer = env->GetFieldID(app_fuse_class, "mBuffer", "[B");
-    if (app_fuse_buffer == nullptr) {
-        ALOGE("Can't find mBuffer");
-        return -1;
-    }
-
-    const jfieldID read_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_READ", "I");
-    if (static_cast<int>(env->GetStaticIntField(app_fuse_class, read_max_fied)) != MAX_READ) {
-        return -1;
-    }
-
-    const jfieldID write_max_fied = env->GetStaticFieldID(app_fuse_class, "MAX_WRITE", "I");
-    if (static_cast<int>(env->GetStaticIntField(app_fuse_class, write_max_fied)) != MAX_WRITE) {
-        return -1;
-    }
-
-    const int result = android::AndroidRuntime::registerNativeMethods(
-            env, "com/android/mtp/AppFuse", gMethods, NELEM(gMethods));
-    if (result < 0) {
-        return -1;
-    }
-
-    return JNI_VERSION_1_4;
-}
diff --git a/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java b/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
index 0762571..36f6fe9 100644
--- a/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
+++ b/packages/MtpDocumentsProvider/perf_tests/src/com/android/mtp/AppFusePerfTest.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
+import android.os.ProxyFileDescriptorCallback;
 import android.os.storage.StorageManager;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -36,38 +37,13 @@
 
 @RunWith(JUnit4.class)
 public class AppFusePerfTest {
+    final static int SIZE = 10 * 1024 * 1024;  // 10MB
+
     @Test
     @LargeTest
     public void testReadWriteFile() throws IOException {
         final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
         final StorageManager storageManager = context.getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final int SIZE = 10 * 1024 * 1024;  // 10MB
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode != INODE) {
-                            throw new FileNotFoundException();
-                        }
-                        return SIZE;
-                    }
-
-                    @Override
-                    public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
-                            throws IOException {
-                        return size;
-                    }
-
-                    @Override
-                    public int writeObjectBytes(
-                            long fileHandle, int inode, long offset, int size, byte[] bytes) {
-                        return size;
-                    }
-                });
-
-        appFuse.mount(storageManager);
 
         final byte[] bytes = new byte[SIZE];
         final int SAMPLES = 100;
@@ -75,22 +51,20 @@
         final double[] writeTime = new double[SAMPLES];
 
         for (int i = 0; i < SAMPLES; i++) {
-            final ParcelFileDescriptor fd = appFuse.openFile(
-                    INODE,
-                    ParcelFileDescriptor.MODE_READ_ONLY);
+            final ParcelFileDescriptor fd = storageManager.openProxyFileDescriptor(
+                    ParcelFileDescriptor.MODE_READ_ONLY, new TestCallback());
             try (final ParcelFileDescriptor.AutoCloseInputStream stream =
                     new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
                 final long startTime = System.nanoTime();
                 stream.read(bytes);
                 readTime[i] = (System.nanoTime() - startTime) / 1000.0 / 1000.0;
             }
-
         }
 
         for (int i = 0; i < SAMPLES; i++) {
-            final ParcelFileDescriptor fd = appFuse.openFile(
-                    INODE,
-                    ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
+            final ParcelFileDescriptor fd = storageManager.openProxyFileDescriptor(
+                    ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE,
+                    new TestCallback());
             try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
                     new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
                 final long startTime = System.nanoTime();
@@ -99,8 +73,6 @@
             }
         }
 
-        appFuse.close();
-
         double readAverage = 0;
         double writeAverage = 0;
         double readSquaredAverage = 0;
@@ -127,28 +99,26 @@
         InstrumentationRegistry.getInstrumentation().sendStatus(Activity.RESULT_OK, results);
     }
 
-    private static class TestCallback implements AppFuse.Callback {
+    private static class TestCallback extends ProxyFileDescriptorCallback {
         @Override
-        public long getFileSize(int inode) throws FileNotFoundException {
-            throw new FileNotFoundException();
+        public long onGetSize() throws ErrnoException {
+            return SIZE;
         }
 
         @Override
-        public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
-                throws IOException {
-            throw new IOException();
+        public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+            return size;
         }
 
         @Override
-        public int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
-                throws IOException {
-            throw new IOException();
+        public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
+            return size;
         }
 
         @Override
-        public void flushFileHandle(long fileHandle) throws IOException {}
+        public void onFsync() throws ErrnoException {}
 
         @Override
-        public void closeFileHandle(long fileHandle) {}
+        public void onRelease() {}
     }
 }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java b/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
deleted file mode 100644
index cd78e61..0000000
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/AppFuse.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2015 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.mtp;
-
-import android.annotation.WorkerThread;
-import android.os.ParcelFileDescriptor;
-import android.os.Process;
-import android.os.storage.StorageManager;
-import android.system.ErrnoException;
-import android.system.OsConstants;
-import android.util.Log;
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.util.Preconditions;
-import com.android.mtp.annotations.UsedByNative;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-
-public class AppFuse {
-    static {
-        System.loadLibrary("appfuse_jni");
-    }
-
-    private static final boolean DEBUG = false;
-
-    /**
-     * Max read amount specified at the FUSE kernel implementation.
-     * The value is copied from sdcard.c.
-     */
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    static final int MAX_READ = 128 * 1024;
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    static final int MAX_WRITE = 256 * 1024;
-
-    private final String mName;
-    private final Callback mCallback;
-
-    /**
-     * Buffer for read bytes request.
-     * Don't use the buffer from the out of AppFuseMessageThread.
-     */
-    private byte[] mBuffer = new byte[Math.max(MAX_READ, MAX_WRITE)];
-
-    private Thread mMessageThread;
-    private ParcelFileDescriptor mDeviceFd;
-
-    AppFuse(String name, Callback callback) {
-        mName = name;
-        mCallback = callback;
-    }
-
-    void mount(StorageManager storageManager) throws IOException {
-        Preconditions.checkState(mDeviceFd == null);
-        mDeviceFd = storageManager.mountAppFuse(mName);
-        mMessageThread = new AppFuseMessageThread(mDeviceFd.dup().detachFd());
-        mMessageThread.start();
-    }
-
-    @VisibleForTesting
-    void close() {
-        try {
-            // Remote side of ParcelFileDescriptor is tracking the close of mDeviceFd, and unmount
-            // the corresponding fuse file system. The mMessageThread will receive ENODEV, and
-            // then terminate itself.
-            mDeviceFd.close();
-            mMessageThread.join();
-        } catch (IOException exp) {
-            Log.e(MtpDocumentsProvider.TAG, "Failed to close device FD.", exp);
-        } catch (InterruptedException exp) {
-            Log.e(MtpDocumentsProvider.TAG, "Failed to terminate message thread.", exp);
-        }
-    }
-
-    /**
-     * Opens a file on app fuse and returns ParcelFileDescriptor.
-     *
-     * @param i ID for opened file.
-     * @param mode Mode for opening file.
-     * @see ParcelFileDescriptor#MODE_READ_ONLY
-     * @see ParcelFileDescriptor#MODE_WRITE_ONLY
-     */
-    public ParcelFileDescriptor openFile(int i, int mode) throws FileNotFoundException {
-        Preconditions.checkArgument(
-                mode == ParcelFileDescriptor.MODE_READ_ONLY ||
-                mode == (ParcelFileDescriptor.MODE_WRITE_ONLY |
-                         ParcelFileDescriptor.MODE_TRUNCATE));
-        return ParcelFileDescriptor.open(new File(
-                getMountPoint(),
-                Integer.toString(i)),
-                mode);
-    }
-
-    File getMountPoint() {
-        return new File("/mnt/appfuse/" + Process.myUid() + "_" + mName);
-    }
-
-    static interface Callback {
-        /**
-         * Returns file size for the given inode.
-         * @param inode
-         * @return File size. Must not be negative.
-         * @throws FileNotFoundException
-         */
-        long getFileSize(int inode) throws FileNotFoundException;
-
-        /**
-         * Returns file bytes for the give inode.
-         * @param inode
-         * @param offset Offset for file bytes.
-         * @param size Size for file bytes.
-         * @param bytes Buffer to store file bytes.
-         * @return Number of read bytes. Must not be negative.
-         * @throws IOException
-         */
-        long readObjectBytes(int inode, long offset, long size, byte[] bytes) throws IOException;
-
-        /**
-         * Handles writing bytes for the give inode.
-         * @param fileHandle
-         * @param inode
-         * @param offset Offset for file bytes.
-         * @param size Size for file bytes.
-         * @param bytes Buffer to store file bytes.
-         * @return Number of read bytes. Must not be negative.
-         * @throws IOException
-         */
-        int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
-                throws IOException, ErrnoException;
-
-        /**
-         * Flushes bytes for file handle.
-         * @param fileHandle
-         * @throws IOException
-         * @throws ErrnoException
-         */
-        void flushFileHandle(long fileHandle) throws IOException, ErrnoException;
-
-        /**
-         * Closes file handle.
-         * @param fileHandle
-         * @throws IOException
-         */
-        void closeFileHandle(long fileHandle) throws IOException, ErrnoException;
-    }
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    @WorkerThread
-    private long getFileSize(int inode) {
-        try {
-            return mCallback.getFileSize(inode);
-        } catch (Exception error) {
-            return -getErrnoFromException(error);
-        }
-    }
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    @WorkerThread
-    private long readObjectBytes(int inode, long offset, long size) {
-        if (offset < 0 || size < 0 || size > MAX_READ) {
-            return -OsConstants.EINVAL;
-        }
-        try {
-            // It's OK to share the same mBuffer among requests because the requests are processed
-            // by AppFuseMessageThread sequentially.
-            return mCallback.readObjectBytes(inode, offset, size, mBuffer);
-        } catch (Exception error) {
-            return -getErrnoFromException(error);
-        }
-    }
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    @WorkerThread
-    private /* unsgined */ int writeObjectBytes(long fileHandler,
-                                                int inode,
-                                                /* unsigned */ long offset,
-                                                /* unsigned */ int size,
-                                                byte[] bytes) {
-        try {
-            return mCallback.writeObjectBytes(fileHandler, inode, offset, size, bytes);
-        } catch (Exception error) {
-            return -getErrnoFromException(error);
-        }
-    }
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    @WorkerThread
-    private int flushFileHandle(long fileHandle) {
-        try {
-            mCallback.flushFileHandle(fileHandle);
-            return 0;
-        } catch (Exception error) {
-            return -getErrnoFromException(error);
-        }
-    }
-
-    @UsedByNative("com_android_mtp_AppFuse.cpp")
-    @WorkerThread
-    private int closeFileHandle(long fileHandle) {
-        try {
-            mCallback.closeFileHandle(fileHandle);
-            return 0;
-        } catch (Exception error) {
-            return -getErrnoFromException(error);
-        }
-    }
-
-    private static int getErrnoFromException(Exception error) {
-        if (DEBUG) {
-            Log.e(MtpDocumentsProvider.TAG, "AppFuse callbacks", error);
-        }
-        if (error instanceof FileNotFoundException) {
-            return OsConstants.ENOENT;
-        } else if (error instanceof IOException) {
-            return OsConstants.EIO;
-        } else if (error instanceof UnsupportedOperationException) {
-            return OsConstants.ENOTSUP;
-        } else if (error instanceof IllegalArgumentException) {
-            return OsConstants.EINVAL;
-        } else {
-            return OsConstants.EIO;
-        }
-    }
-
-    private native void native_start_app_fuse_loop(int fd);
-
-    private class AppFuseMessageThread extends Thread {
-        /**
-         * File descriptor used by native loop.
-         * It's owned by native loop and does not need to close here.
-         */
-        private final int mRawFd;
-
-        AppFuseMessageThread(int fd) {
-            super("AppFuseMessageThread");
-            mRawFd = fd;
-        }
-
-        @Override
-        public void run() {
-            native_start_app_fuse_loop(mRawFd);
-        }
-    }
-}
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
index 6b2c1ee..8b0e610 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
@@ -33,6 +33,7 @@
 import android.os.CancellationSignal;
 import android.os.FileUtils;
 import android.os.ParcelFileDescriptor;
+import android.os.ProxyFileDescriptorCallback;
 import android.os.storage.StorageManager;
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Path;
@@ -41,6 +42,7 @@
 import android.provider.DocumentsProvider;
 import android.provider.Settings;
 import android.system.ErrnoException;
+import android.system.OsConstants;
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
@@ -54,6 +56,8 @@
 import java.util.Map;
 import java.util.concurrent.TimeoutException;
 
+import libcore.io.IoUtils;
+
 /**
  * DocumentsProvider for MTP devices.
  */
@@ -84,9 +88,9 @@
     private RootScanner mRootScanner;
     private Resources mResources;
     private MtpDatabase mDatabase;
-    private AppFuse mAppFuse;
     private ServiceIntentSender mIntentSender;
     private Context mContext;
+    private StorageManager mStorageManager;
 
     /**
      * Provides singleton instance to MtpDocumentsService.
@@ -105,8 +109,8 @@
         mDeviceToolkits = new HashMap<Integer, DeviceToolkit>();
         mDatabase = new MtpDatabase(getContext(), MtpDatabaseConstants.FLAG_DATABASE_IN_FILE);
         mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase);
-        mAppFuse = new AppFuse(TAG, new AppFuseCallback());
         mIntentSender = new ServiceIntentSender(getContext());
+        mStorageManager = getContext().getSystemService(StorageManager.class);
 
         // Check boot count and cleans database if it's first time to launch MtpDocumentsProvider
         // after booting.
@@ -129,14 +133,6 @@
             return false;
         }
 
-        // TODO: Mount AppFuse on demands.
-        try {
-            mAppFuse.mount(getContext().getSystemService(StorageManager.class));
-        } catch (IOException error) {
-            Log.e(TAG, "Failed to start app fuse.", error);
-            return false;
-        }
-
         resume();
         return true;
     }
@@ -157,16 +153,9 @@
         mDeviceToolkits = new HashMap<Integer, DeviceToolkit>();
         mDatabase = database;
         mRootScanner = new RootScanner(mResolver, mMtpManager, mDatabase);
-        mAppFuse = new AppFuse(TAG, new AppFuseCallback());
         mIntentSender = intentSender;
+        mStorageManager = storageManager;
 
-        // TODO: Mount AppFuse on demands.
-        try {
-            mAppFuse.mount(storageManager);
-        } catch (IOException e) {
-            Log.e(TAG, "Failed to start app fuse.", e);
-            return false;
-        }
         resume();
         return true;
     }
@@ -252,7 +241,10 @@
                 }
                 if (MtpDeviceRecord.isPartialReadSupported(
                         device.operationsSupported, fileSize)) {
-                    return mAppFuse.openFile(Integer.parseInt(documentId), modeFlag);
+
+                    return mStorageManager.openProxyFileDescriptor(
+                            modeFlag,
+                            new MtpProxyFileDescriptorCallback(Integer.parseInt(documentId)));
                 } else {
                     // If getPartialObject{|64} are not supported for the device, returns
                     // non-seekable pipe FD instead.
@@ -262,7 +254,9 @@
                 // TODO: Clear the parent document loader task (if exists) and call notify
                 // when writing is completed.
                 if (MtpDeviceRecord.isWritingSupported(device.operationsSupported)) {
-                    return mAppFuse.openFile(Integer.parseInt(documentId), modeFlag);
+                    return mStorageManager.openProxyFileDescriptor(
+                            modeFlag,
+                            new MtpProxyFileDescriptorCallback(Integer.parseInt(documentId)));
                 } else {
                     throw new UnsupportedOperationException(
                             "The device does not support writing operation.");
@@ -586,7 +580,6 @@
                 throw new RuntimeException(e);
             } finally {
                 mDatabase.close();
-                mAppFuse.close();
                 super.shutdown();
             }
         }
@@ -693,72 +686,92 @@
         }
     }
 
-    private class AppFuseCallback implements AppFuse.Callback {
-        private final Map<Long, MtpFileWriter> mWriters = new HashMap<>();
+    private class MtpProxyFileDescriptorCallback extends ProxyFileDescriptorCallback {
+        private final int mInode;
+        private MtpFileWriter mWriter;
 
-        @Override
-        public long getFileSize(int inode) throws FileNotFoundException {
-            return MtpDocumentsProvider.this.getFileSize(String.valueOf(inode));
+        MtpProxyFileDescriptorCallback(int inode) {
+            mInode = inode;
         }
 
         @Override
-        public long readObjectBytes(
-                int inode, long offset, long size, byte[] buffer) throws IOException {
-            final Identifier identifier = mDatabase.createIdentifier(Integer.toString(inode));
-            final MtpDeviceRecord record = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
-
-            if (MtpDeviceRecord.isSupported(
-                    record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT_64)) {
-                return mMtpManager.getPartialObject64(
-                        identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
-            }
-
-            if (0 <= offset && offset <= 0xffffffffL && MtpDeviceRecord.isSupported(
-                    record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT)) {
-                return mMtpManager.getPartialObject(
-                        identifier.mDeviceId, identifier.mObjectHandle, offset, size, buffer);
-            }
-
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public int writeObjectBytes(
-                long fileHandle, int inode, long offset, int size, byte[] bytes)
-                throws IOException, ErrnoException {
-            final MtpFileWriter writer;
-            if (mWriters.containsKey(fileHandle)) {
-                writer = mWriters.get(fileHandle);
-            } else {
-                writer = new MtpFileWriter(mContext, String.valueOf(inode));
-                mWriters.put(fileHandle, writer);
-            }
-            return writer.write(offset, size, bytes);
-        }
-
-        @Override
-        public void flushFileHandle(long fileHandle) throws IOException, ErrnoException {
-            final MtpFileWriter writer = mWriters.get(fileHandle);
-            if (writer == null) {
-                // File handle for reading.
-                return;
-            }
-            final MtpDeviceRecord device = getDeviceToolkit(
-                    mDatabase.createIdentifier(writer.getDocumentId()).mDeviceId).mDeviceRecord;
-            writer.flush(mMtpManager, mDatabase, device.operationsSupported);
-        }
-
-        @Override
-        public void closeFileHandle(long fileHandle) throws IOException, ErrnoException {
-            final MtpFileWriter writer = mWriters.get(fileHandle);
-            if (writer == null) {
-                // File handle for reading.
-                return;
-            }
+        public long onGetSize() throws ErrnoException {
             try {
-                writer.close();
+                return getFileSize(String.valueOf(mInode));
+            } catch (FileNotFoundException e) {
+                Log.e(TAG, e.getMessage(), e);
+                throw new ErrnoException("onGetSize", OsConstants.ENOENT);
+            }
+        }
+
+        @Override
+        public int onRead(long offset, int size, byte[] data) throws ErrnoException {
+            try {
+                final Identifier identifier = mDatabase.createIdentifier(Integer.toString(mInode));
+                final MtpDeviceRecord record = getDeviceToolkit(identifier.mDeviceId).mDeviceRecord;
+                if (MtpDeviceRecord.isSupported(
+                        record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT_64)) {
+
+                        return (int) mMtpManager.getPartialObject64(
+                                identifier.mDeviceId, identifier.mObjectHandle, offset, size, data);
+
+                }
+                if (0 <= offset && offset <= 0xffffffffL && MtpDeviceRecord.isSupported(
+                        record.operationsSupported, MtpConstants.OPERATION_GET_PARTIAL_OBJECT)) {
+                    return (int) mMtpManager.getPartialObject(
+                            identifier.mDeviceId, identifier.mObjectHandle, offset, size, data);
+                }
+                throw new ErrnoException("onRead", OsConstants.ENOTSUP);
+            } catch (IOException e) {
+                Log.e(TAG, e.getMessage(), e);
+                throw new ErrnoException("onRead", OsConstants.EIO);
+            }
+        }
+
+        @Override
+        public int onWrite(long offset, int size, byte[] data) throws ErrnoException {
+            try {
+                if (mWriter == null) {
+                    mWriter = new MtpFileWriter(mContext, String.valueOf(mInode));
+                }
+                return mWriter.write(offset, size, data);
+            } catch (IOException e) {
+                Log.e(TAG, e.getMessage(), e);
+                throw new ErrnoException("onWrite", OsConstants.EIO);
+            }
+        }
+
+        @Override
+        public void onFsync() throws ErrnoException {
+            tryFsync();
+        }
+
+        @Override
+        public void onRelease() {
+            try {
+                tryFsync();
+            } catch (ErrnoException error) {
+                // Cannot recover from the error at onRelease. Client app should use fsync to
+                // ensure the provider writes data correctly.
+                Log.e(TAG, "Cannot recover from the error at onRelease.", error);
             } finally {
-                mWriters.remove(fileHandle);
+                if (mWriter != null) {
+                    IoUtils.closeQuietly(mWriter);
+                }
+            }
+        }
+
+        private void tryFsync() throws ErrnoException {
+            try {
+                if (mWriter != null) {
+                    final MtpDeviceRecord device =
+                            getDeviceToolkit(mDatabase.createIdentifier(
+                                    mWriter.getDocumentId()).mDeviceId).mDeviceRecord;
+                    mWriter.flush(mMtpManager, mDatabase, device.operationsSupported);
+                }
+            } catch (IOException e) {
+                Log.e(TAG, e.getMessage(), e);
+                throw new ErrnoException("onWrite", OsConstants.EIO);
             }
         }
     }
diff --git a/packages/MtpDocumentsProvider/tests/Android.mk b/packages/MtpDocumentsProvider/tests/Android.mk
index 8538379..e50d6fb 100644
--- a/packages/MtpDocumentsProvider/tests/Android.mk
+++ b/packages/MtpDocumentsProvider/tests/Android.mk
@@ -4,6 +4,7 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := MtpDocumentsProviderTests
 LOCAL_INSTRUMENTATION_FOR := MtpDocumentsProvider
 LOCAL_CERTIFICATE := media
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
deleted file mode 100644
index e421de71..0000000
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/AppFuseTest.java
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2015 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.mtp;
-
-import android.os.ParcelFileDescriptor;
-import android.os.storage.StorageManager;
-import android.system.ErrnoException;
-import android.system.Os;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import libcore.io.IoUtils;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.Arrays;
-
-@MediumTest
-public class AppFuseTest extends AndroidTestCase {
-    public void testMount() throws ErrnoException, IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final AppFuse appFuse = new AppFuse("test", new TestCallback());
-        appFuse.mount(storageManager);
-        final File file = appFuse.getMountPoint();
-        assertTrue(file.isDirectory());
-        assertEquals(1, Os.stat(file.getPath()).st_ino);
-        appFuse.close();
-        assertTrue(1 != Os.stat(file.getPath()).st_ino);
-    }
-
-    public void testOpenFile() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (INODE == inode) {
-                            return 1024;
-                        }
-                        throw new FileNotFoundException();
-                    }
-                });
-        appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(
-                INODE, ParcelFileDescriptor.MODE_READ_ONLY);
-        fd.close();
-        appFuse.close();
-    }
-
-    public void testOpenFile_fileNotFound() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final AppFuse appFuse = new AppFuse("test", new TestCallback());
-        appFuse.mount(storageManager);
-        try {
-            appFuse.openFile(INODE, ParcelFileDescriptor.MODE_READ_ONLY);
-            fail();
-        } catch (FileNotFoundException exp) {}
-        appFuse.close();
-    }
-
-    public void testOpenFile_illegalMode() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final AppFuse appFuse = new AppFuse("test", new TestCallback());
-        appFuse.mount(storageManager);
-        try {
-            appFuse.openFile(INODE, ParcelFileDescriptor.MODE_READ_WRITE);
-            fail();
-        } catch (IllegalArgumentException exp) {}
-        appFuse.close();
-    }
-
-    public void testReadFile() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int fileInode = 10;
-        final byte[] fileBytes = new byte[] { 'a', 'b', 'c', 'd', 'e' };
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode == fileInode) {
-                            return fileBytes.length;
-                        }
-                        return super.getFileSize(inode);
-                    }
-
-                    @Override
-                    public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
-                            throws IOException {
-                        if (inode == fileInode) {
-                            int i = 0;
-                            while (i < size && i + offset < fileBytes.length)  {
-                                bytes[i] = fileBytes[(int) (i + offset)];
-                                i++;
-                            }
-                            return i;
-                        }
-                        return super.readObjectBytes(inode, offset, size, bytes);
-                    }
-                });
-        appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(
-                fileInode, ParcelFileDescriptor.MODE_READ_ONLY);
-        try (final ParcelFileDescriptor.AutoCloseInputStream stream =
-                new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
-            final byte[] buffer = new byte[1024];
-            final int size = stream.read(buffer, 0, buffer.length);
-            assertEquals(5, size);
-        }
-        appFuse.close();
-    }
-
-    public void testWriteFile() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final byte[] resultBytes = new byte[5];
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode != INODE) {
-                            throw new FileNotFoundException();
-                        }
-                        return resultBytes.length;
-                    }
-
-                    @Override
-                    public int writeObjectBytes(
-                            long fileHandle, int inode, long offset, int size, byte[] bytes) {
-                        for (int i = 0; i < size; i++) {
-                            resultBytes[(int)(offset + i)] = bytes[i];
-                        }
-                        return size;
-                    }
-                });
-        appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(
-                INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
-        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
-                new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
-            stream.write('a');
-            stream.write('b');
-            stream.write('c');
-            stream.write('d');
-            stream.write('e');
-        }
-        final byte[] BYTES = new byte[] { 'a', 'b', 'c', 'd', 'e' };
-        assertTrue(Arrays.equals(BYTES, resultBytes));
-        appFuse.close();
-    }
-
-    public void testWriteFile_writeError() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode != INODE) {
-                            throw new FileNotFoundException();
-                        }
-                        return 5;
-                    }
-                });
-        appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(
-                INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
-        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
-                new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
-            stream.write('a');
-            fail();
-        } catch (IOException e) {
-        }
-        appFuse.close();
-    }
-
-    public void testWriteFile_flushError() throws IOException {
-        final StorageManager storageManager = getContext().getSystemService(StorageManager.class);
-        final int INODE = 10;
-        final AppFuse appFuse = new AppFuse(
-                "test",
-                new TestCallback() {
-                    @Override
-                    public long getFileSize(int inode) throws FileNotFoundException {
-                        if (inode != INODE) {
-                            throw new FileNotFoundException();
-                        }
-                        return 5;
-                    }
-
-                    @Override
-                    public int writeObjectBytes(
-                            long fileHandle, int inode, long offset, int size, byte[] bytes) {
-                        return size;
-                    }
-
-                    @Override
-                    public void flushFileHandle(long fileHandle) throws IOException {
-                        throw new IOException();
-                    }
-                });
-        appFuse.mount(storageManager);
-        final ParcelFileDescriptor fd = appFuse.openFile(
-                INODE, ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_TRUNCATE);
-        try (final ParcelFileDescriptor.AutoCloseOutputStream stream =
-                new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
-            stream.write('a');
-            try {
-                IoUtils.close(fd.getFileDescriptor());
-                fail();
-            } catch (IOException e) {
-            }
-        }
-        appFuse.close();
-    }
-
-    private static class TestCallback implements AppFuse.Callback {
-        @Override
-        public long getFileSize(int inode) throws FileNotFoundException {
-            throw new FileNotFoundException();
-        }
-
-        @Override
-        public long readObjectBytes(int inode, long offset, long size, byte[] bytes)
-                throws IOException {
-            throw new IOException();
-        }
-
-        @Override
-        public int writeObjectBytes(long fileHandle, int inode, long offset, int size, byte[] bytes)
-                throws IOException {
-            throw new IOException();
-        }
-
-        @Override
-        public void flushFileHandle(long fileHandle) throws IOException {}
-
-        @Override
-        public void closeFileHandle(long fileHandle) {}
-    }
-}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
index a9d35e1..491e24d 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDocumentsProviderTest.java
@@ -557,6 +557,7 @@
             try (ParcelFileDescriptor.AutoCloseOutputStream stream =
                     new ParcelFileDescriptor.AutoCloseOutputStream(fd)) {
                 stream.write("Hello".getBytes());
+                fd.getFileDescriptor().sync();
             }
         }
         {
diff --git a/packages/SettingsLib/res/values-bg/arrays.xml b/packages/SettingsLib/res/values-bg/arrays.xml
index d220a07..93d547d 100644
--- a/packages/SettingsLib/res/values-bg/arrays.xml
+++ b/packages/SettingsLib/res/values-bg/arrays.xml
@@ -109,12 +109,12 @@
     <item msgid="8883739882299884241">"Стерео"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Предпоч. кач. на звука (990 или 909 кб/сек)"</item>
+    <item msgid="2944889121850394020">"Предпоч. кач. на звука (990 или 909 кб/сек)QM"</item>
     <item msgid="138837449700903545">"Стандартно (660 или 606 кб/сек)"</item>
     <item msgid="4777177307869441982">"Предпоч. връзка (330 или 303 кб/сек)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Предпоч. кач. на звука (990 или 909 кб/сек)"</item>
+    <item msgid="172302906231378902">"Предпоч. кач. на звука (990 или 909 кб/сек)The QM tool is not responding at the moment, and I am not able to check the status of the query."</item>
     <item msgid="9091111147684472529">"Стандартно (660 или 606 кб/сек)"</item>
     <item msgid="3367904477834831032">"Предпоч. връзка (330 или 303 кб/сек)"</item>
   </string-array>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index b8b8ce4..59eb2eb 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -172,8 +172,8 @@
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Inhabilitar volumen absoluto"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Códec del audio Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Selecciona el códec A2DP de Bluetooth preferido"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frecuencia de la muestra del audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selecciona la frecuencia de la muestra preferida del códec A2DP de Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frecuencia de muestreo del audio Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selecciona la frecuencia de muestreo preferida del códec A2DP de Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por muestra del audio Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Selecciona los bits por muestra del códec A2DP de Bluetooth preferidos"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal del audio Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-es/arrays.xml b/packages/SettingsLib/res/values-es/arrays.xml
index 1cfbe7e..a2ce809 100644
--- a/packages/SettingsLib/res/values-es/arrays.xml
+++ b/packages/SettingsLib/res/values-es/arrays.xml
@@ -109,12 +109,12 @@
     <item msgid="8883739882299884241">"Estéreo"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Calidad son. pref. (990 kbps / 909 kbps)"</item>
+    <item msgid="2944889121850394020">"Calidad sonido pref. (990 kbps/909 kbps)"</item>
     <item msgid="138837449700903545">"Estándar (660 kbps / 606 kbps)"</item>
     <item msgid="4777177307869441982">"Conexión preferida (330 kbps / 303 kbps)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Calidad son. pref. (990 kbps / 909 kbps)"</item>
+    <item msgid="172302906231378902">"Calidad sonido pref. (990 kbps/909 kbps)"</item>
     <item msgid="9091111147684472529">"Estándar (660 kbps / 606 kbps)"</item>
     <item msgid="3367904477834831032">"Conexión preferida (330 kbps / 303 kbps)"</item>
   </string-array>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 9eeeccb..aedc9ca 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -171,7 +171,7 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Données cellulaires toujours actives"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Désactiver le volume absolu"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec audio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Sélectionnez le codec Bluetooth A2DP"</string>
+    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Sélectionnez le codec Bluetooth A2DP préféré"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taux d\'échantillonnage pour l\'audio Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Sélectionnez le taux d\'échantillonnage préféré pour le codec Bluetooth A2DP"</string>
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits par échantillon pour l\'audio Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-hr/arrays.xml b/packages/SettingsLib/res/values-hr/arrays.xml
index 114337a..06e3f51 100644
--- a/packages/SettingsLib/res/values-hr/arrays.xml
+++ b/packages/SettingsLib/res/values-hr/arrays.xml
@@ -109,14 +109,14 @@
     <item msgid="8883739882299884241">"Stereo"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Željena kval. zvuka (990 kbps/909 kbps)"</item>
-    <item msgid="138837449700903545">"Standardna (660 kbps/606 kbps)"</item>
-    <item msgid="4777177307869441982">"Željeno povezivanje (330 kbps/303 kbps)"</item>
+    <item msgid="2944889121850394020">"Željena kval. zvuka (990 kb/s / 909 kb/s)"</item>
+    <item msgid="138837449700903545">"Standardna (660 kb/s / 606 kb/s)"</item>
+    <item msgid="4777177307869441982">"Željeno povezivanje (330 kb/s / 303 kb/s)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Željena kval. zvuka (990 kbps/909 kbps)"</item>
-    <item msgid="9091111147684472529">"Standardna (660 kbps/606 kbps)"</item>
-    <item msgid="3367904477834831032">"Željeno povezivanje (330 kbps/303 kbps)"</item>
+    <item msgid="172302906231378902">"Željena kval. zvuka (990 kb/s / 909 kb/s)"</item>
+    <item msgid="9091111147684472529">"Standardna (660 kb/s / 606 kb/s)"</item>
+    <item msgid="3367904477834831032">"Željeno povezivanje (330 kb/s / 303 kb/s)"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Isključeno"</item>
diff --git a/packages/SettingsLib/res/values-hy/arrays.xml b/packages/SettingsLib/res/values-hy/arrays.xml
index ab810bf..1d72787 100644
--- a/packages/SettingsLib/res/values-hy/arrays.xml
+++ b/packages/SettingsLib/res/values-hy/arrays.xml
@@ -109,14 +109,14 @@
     <item msgid="8883739882299884241">"Ստերեո"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Նախընտրելի է ձայնի որակը (990 կբ/վ / 909 կբ/վ)"</item>
+    <item msgid="2944889121850394020">"Նախընտրած ձայնի որակ (990 կբ/վ / 909 կբ/վ)"</item>
     <item msgid="138837449700903545">"Ստանդարտ (660 կբ/վ / 606 կբ/վ)"</item>
-    <item msgid="4777177307869441982">"Նախընտրելի է կապը (330 կբ/վ / 303 կբ/վ)"</item>
+    <item msgid="4777177307869441982">"Նախընտրած կապ (330 կբ/վ / 303 կբ/վ)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Նախընտրելի է ձայնի որակը (990 կբ/վ / 909 կբ/վ)"</item>
+    <item msgid="172302906231378902">"Նախընտրած ձայնի որակ (990 կբ/վ / 909 կբ/վ)"</item>
     <item msgid="9091111147684472529">"Ստանդարտ (660 կբ/վ / 606 կբ/վ)"</item>
-    <item msgid="3367904477834831032">"Նախընտրելի է կապը (330 կբ/վ / 303 կբ/վ)"</item>
+    <item msgid="3367904477834831032">"Նախընտրած կապ (330 կբ/վ / 303 կբ/վ)"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Անջատված է"</item>
diff --git a/packages/SettingsLib/res/values-iw/arrays.xml b/packages/SettingsLib/res/values-iw/arrays.xml
index 621e14d..f1e7be9 100644
--- a/packages/SettingsLib/res/values-iw/arrays.xml
+++ b/packages/SettingsLib/res/values-iw/arrays.xml
@@ -88,15 +88,15 @@
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
     <item msgid="6694044160540313386">"ברירת מחדל"</item>
-    <item msgid="5618929009984956469">"16 סיביות/דגימה"</item>
-    <item msgid="3412640499234627248">"24 סיביות/דגימה"</item>
-    <item msgid="121583001492929387">"32 סיביות/דגימה"</item>
+    <item msgid="5618929009984956469">"16 סיביות לדגימה"</item>
+    <item msgid="3412640499234627248">"24 סיביות לדגימה"</item>
+    <item msgid="121583001492929387">"32 סיביות לדגימה"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
     <item msgid="5091076677792306320">"ברירת מחדל"</item>
-    <item msgid="4726688794884191540">"16 סיביות/דגימה"</item>
-    <item msgid="305344756485516870">"24 סיביות/דגימה"</item>
-    <item msgid="244568657919675099">"32 סיביות/דגימה"</item>
+    <item msgid="4726688794884191540">"16 סיביות לדגימה"</item>
+    <item msgid="305344756485516870">"24 סיביות לדגימה"</item>
+    <item msgid="244568657919675099">"32 סיביות לדגימה"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
     <item msgid="13423709606339855">"ברירת מחדל"</item>
diff --git a/packages/SettingsLib/res/values-kk/arrays.xml b/packages/SettingsLib/res/values-kk/arrays.xml
index e253a79..4c1c819 100644
--- a/packages/SettingsLib/res/values-kk/arrays.xml
+++ b/packages/SettingsLib/res/values-kk/arrays.xml
@@ -109,14 +109,14 @@
     <item msgid="8883739882299884241">"Стерео"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Таңдаулы дыбыс сапасы (990 кб/сек не 909 кб/сек)"</item>
-    <item msgid="138837449700903545">"Стандартты (660 кб/сек не 606 кб/сек)"</item>
-    <item msgid="4777177307869441982">"Таңдаулы байланыс (330 кб/сек не 303 кб/сек)"</item>
+    <item msgid="2944889121850394020">"Таңдаулы дыбыс сапасы (990 кбит/с не 909 кбит/с)"</item>
+    <item msgid="138837449700903545">"Стандартты (660 кбит/с не 606 кбит/с)"</item>
+    <item msgid="4777177307869441982">"Таңдаулы байланыс (330 кбит/с не 303 кбит/с)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Таңдаулы дыбыс сапасы (990 кб/сек не 909 кб/сек)"</item>
-    <item msgid="9091111147684472529">"Стандартты (660 кб/сек не 606 кб/сек)"</item>
-    <item msgid="3367904477834831032">"Таңдаулы байланыс (330 кб/сек не 303 кб/сек)"</item>
+    <item msgid="172302906231378902">"Таңдаулы дыбыс сапасы (990 кбит/с не 909 кбит/с)"</item>
+    <item msgid="9091111147684472529">"Стандартты (660 кбит/с не 606 кбит/с)"</item>
+    <item msgid="3367904477834831032">"Таңдаулы байланыс (330 кбит/с не 303 кбит/с)"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Өшірулі"</item>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 505b118..862d06f 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -170,7 +170,7 @@
     <string name="wifi_allow_scan_with_traffic" msgid="3601853081178265786">"Wi‑Fi роумингін іздеулерге әрқашан рұқсат ету"</string>
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Ұялы деректер әрқашан белсенді"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Абсолютті дыбыс деңгейін өшіру"</string>
-    <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудимазмұны кодегі"</string>
+    <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Bluetooth аудимазмұн кодегі"</string>
     <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Таңдаулы Bluetooth A2DP кодегін таңдау"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Bluetooth аудиомазмұны бойынша үлгі жиілігі"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Таңдаулы Bluetooth A2DP кодегі бойынша үлгі жиілігі"</string>
diff --git a/packages/SettingsLib/res/values-mk/arrays.xml b/packages/SettingsLib/res/values-mk/arrays.xml
index e7a9563..55e60a7 100644
--- a/packages/SettingsLib/res/values-mk/arrays.xml
+++ b/packages/SettingsLib/res/values-mk/arrays.xml
@@ -88,15 +88,15 @@
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
     <item msgid="6694044160540313386">"Стандардно"</item>
-    <item msgid="5618929009984956469">"16 бита/примерок"</item>
-    <item msgid="3412640499234627248">"24 бита/примерок"</item>
-    <item msgid="121583001492929387">"32 бита/примерок"</item>
+    <item msgid="5618929009984956469">"16 бита/семпл"</item>
+    <item msgid="3412640499234627248">"24 бита/семпл"</item>
+    <item msgid="121583001492929387">"32 бита/семпл"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
     <item msgid="5091076677792306320">"Стандардно"</item>
-    <item msgid="4726688794884191540">"16 бита/примерок"</item>
-    <item msgid="305344756485516870">"24 бита/примерок"</item>
-    <item msgid="244568657919675099">"32 бита/примерок"</item>
+    <item msgid="4726688794884191540">"16 бита/семпл"</item>
+    <item msgid="305344756485516870">"24 бита/семпл"</item>
+    <item msgid="244568657919675099">"32 бита/семпл"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
     <item msgid="13423709606339855">"Стандардно"</item>
@@ -109,12 +109,12 @@
     <item msgid="8883739882299884241">"Стерео"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Прет. квалитет на звук (990kbps/909kbps)"</item>
+    <item msgid="2944889121850394020">"Претпочитан квалитет (990kbps/909kbps)"</item>
     <item msgid="138837449700903545">"Стандардно (660kbps/606kbps)"</item>
     <item msgid="4777177307869441982">"Претпочитана врска (330kbps/303kbps)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Прет. квалитет на звук (990kbps/909kbps)"</item>
+    <item msgid="172302906231378902">"Претпочитан квалитет (990kbps/909kbps)"</item>
     <item msgid="9091111147684472529">"Стандардно (660kbps/606kbps)"</item>
     <item msgid="3367904477834831032">"Претпочитана врска (330kbps/303kbps)"</item>
   </string-array>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index eb0760b..e248804 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -171,15 +171,15 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Мобилниот интернет е секогаш активен"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Оневозможете апсолутна јачина на звук"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Кодек за аудио преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Изберете претпочитан кодек за A2DP преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Стапка на примерок аудио преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Изберете претпочитана стапка на примерок за кодек за A2DP преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Бита по примерок аудио преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Изберете претпочитани бита по примерок кодек за A2DP преку Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Изберете претпочитан A2DP кодек преку Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Стапка на семпл преку Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Изберете претпочитана стапка на семпл за A2DP кодекот преку Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Аудио бит-по-семпл преку Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Изберете претпочитан бит-по-семпл за A2DP кодекот преку Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Режим на канал за аудио преку Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Изберете претпочитан режим на канал за кодек за A2DP преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Квалитет на репродукција LDAC на аудио преку Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Изберете претпочитан квалитет на репродукција LDAC на кодек за A2DP преку Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Квалитет на LDAC-аудио репродукција преку Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Изберете претпочитан квалитет на LDAC-репродукција на A2DP кодекот преку Bluetooth"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Покажи ги опциите за безжичен приказ на сертификат"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Зголеми Wi‑Fi ниво на пријавување, прикажи по SSID RSSI во Wi‑Fi бирач"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Кога е вклучено, Wi-Fi ќе биде поагресивно при предавање на поврзувањето со податоци на мобилната мрежа при слаб сигнал на Wi-Fi."</string>
diff --git a/packages/SettingsLib/res/values-my/arrays.xml b/packages/SettingsLib/res/values-my/arrays.xml
index a43eb94..f5e3824 100644
--- a/packages/SettingsLib/res/values-my/arrays.xml
+++ b/packages/SettingsLib/res/values-my/arrays.xml
@@ -109,14 +109,14 @@
     <item msgid="8883739882299884241">"စတီရီယို"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"ပိုမိုနှစ်သက်သည့် အသံအရည်အသွေး (၉၉၀kbps/၉၀၉kbps)"</item>
+    <item msgid="2944889121850394020">"လိုလားသည့်အသံအရည်အသွေး (၉၉၀kbps/၉၀၉kbps)"</item>
     <item msgid="138837449700903545">"ပုံမှန် (၆၆၀kbps/၆၀၆kbps)"</item>
-    <item msgid="4777177307869441982">"ပိုမိုနှစ်သက်သည့် မြန်နှုန်း (၃၃၀kbps/၃၀၃kbps)"</item>
+    <item msgid="4777177307869441982">"လိုလားသည့် မြန်နှုန်း (၃၃၀kbps/၃၀၃kbps)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"ပိုမိုနှစ်သက်သည့် အသံအရည်အသွေး (၉၉၀kbps/၉၀၉kbps)"</item>
+    <item msgid="172302906231378902">"လိုလားသည့်အသံအရည်အသွေး (၉၉၀kbps/၉၀၉kbps)"</item>
     <item msgid="9091111147684472529">"ပုံမှန် (၆၆၀kbps/၆၀၆kbps)"</item>
-    <item msgid="3367904477834831032">"ပိုမိုနှစ်သက်သည့် ချိတ်ဆက်မှု (၃၃၀kbps/၃၀၃kbps)"</item>
+    <item msgid="3367904477834831032">"လိုလားသည့် ချိတ်ဆက်မှု (၃၃၀kbps/၃၀၃kbps)"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"ပိတ်ပါ"</item>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 3b70cc3..941b240 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -171,15 +171,15 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"ဆဲလ်လူလာဒေတာ အမြဲတမ်းဖွင့်ထားသည်"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"ပကတိ အသံနှုန်း သတ်မှတ်ချက် ပိတ်ရန်"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"ဘလူးတုသ်အသံ ကိုးဒက်ခ်"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"ပိုမိုနှစ်သက်သည့် ဘလူးတုသ် A2DP ကိုးဒက်ခ်ကို ရွေးချယ်ပါ"</string>
+    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"လိုလားသည့် ဘလူးတုသ် A2DP ကိုးဒက်ခ်ကို ရွေးချယ်ပါ"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ဘလူးတုသ်အသံနမူနာနှုန်း"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"ပိုမိုနှစ်သက်သည့် ဘလူးတုသ် A2DP ကိုးဒက်ခ် အသံနမူနာနှုန်းကို ရွေးချယ်ပါ"</string>
+    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"လိုလားသည့် ဘလူးတုသ် A2DP ကိုးဒက်ခ် အသံနမူနာနှုန်းကို ရွေးချယ်ပါ"</string>
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"နမူနာတစ်ခုစီတွင် ပါဝင်သော ဘလူးတုသ်အသံပမာဏ Bits"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"ပိုမိုနှစ်သက်သည့် နမူနာတစ်ခုစီတွင် ပါဝင်သော ဘလူးတုသ် A2DP ကိုးဒက်ခ် Bits ကို ရွေးပါ"</string>
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"နမူနာတစ်ခုချင်းစီအတွက် လိုလားသည့် ဘလူးတုသ် A2DP ကိုးဒက်ခ် Bits ကို ရွေးပါ"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ဘလူးတုသ်အသံချန်နယ်မုဒ်"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"ပိုမိုနှစ်သက်သည့် ဘလူးတုသ် A2DP ကိုးဒက်ခ် ချန်နယ်မုဒ်ကိုရွေးချယ်ပါ"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"ဘလူးတုသ်အသံ LDAC ကြည့်ရန် အရည်အသွေး"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"ပိုမိုနှစ်သက်သည့် ဘလူးတုသ်အသံ LDAC ကြည့်ရန် အရည်အသွေးကို ရွေးချယ်ပါ"</string>
+    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"လိုလားသည့် ဘလူးတုသ် A2DP ကိုးဒက်ခ် ချန်နယ်မုဒ်ကို ရွေးချယ်ပါ"</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"LDAC ဖွင့်ရန် ဘလူးတုသ်အသံ အရည်အသွေး"</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"LDAC ဖွင့်ရန် လိုလားသည့် ဘလူးတုသ်အသံ အရည်အသွေးကို ရွေးချယ်ပါ"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"ကြိုးမဲ့ အခင်းအကျင်း အသိအမှတ်ပြုလက်မှတ်အတွက် ရွေးချယ်စရာများပြရန်"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Wi‑Fi မှတ်တမ်းတင်ခြင်း နှုန်းအားမြင့်ကာ၊ Wi‑Fi ရွေးရာတွင် SSID RSSI ဖြင့်ပြပါ"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"ဖွင့်ထားလျှင်၊ Wi‑Fi မှ ဆယ်လူလာသို့ အချက်လက် ချိတ်ဆက်မှုအား လွှဲပြောင်းရာ၌ ပိုမိုထိရောက်ပါသည်၊ WIFI အားနည်းနေချိန်တွင်"</string>
diff --git a/packages/SettingsLib/res/values-pa/arrays.xml b/packages/SettingsLib/res/values-pa/arrays.xml
index a53d534..670a69b 100644
--- a/packages/SettingsLib/res/values-pa/arrays.xml
+++ b/packages/SettingsLib/res/values-pa/arrays.xml
@@ -88,15 +88,15 @@
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
     <item msgid="6694044160540313386">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
-    <item msgid="5618929009984956469">"16 ਬਿੱਟ/ਨਮੂਨਾ"</item>
-    <item msgid="3412640499234627248">"24 ਬਿੱਟ/ਨਮੂਨਾ"</item>
-    <item msgid="121583001492929387">"32 ਬਿੱਟ/ਨਮੂਨਾ"</item>
+    <item msgid="5618929009984956469">"16 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
+    <item msgid="3412640499234627248">"24 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
+    <item msgid="121583001492929387">"32 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries">
     <item msgid="5091076677792306320">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
-    <item msgid="4726688794884191540">"16 ਬਿੱਟ/ਨਮੂਨਾ"</item>
-    <item msgid="305344756485516870">"24 ਬਿੱਟ/ਨਮੂਨਾ"</item>
-    <item msgid="244568657919675099">"32 ਬਿੱਟ/ਨਮੂਨਾ"</item>
+    <item msgid="4726688794884191540">"16 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
+    <item msgid="305344756485516870">"24 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
+    <item msgid="244568657919675099">"32 ਬਿਟਾਂ/ਨਮੂਨਾ"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
     <item msgid="13423709606339855">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</item>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index f824746..9f717e0 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -174,8 +174,8 @@
     <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"ਤਰਜੀਹੀ ਬਲੂਟੁੱਥ A2DP ਕੋਡੇਕ ਚੁਣੋ"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਨਮੂਨਾ ਦਰ"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"ਤਰਜੀਹੀ ਬਲੂਟੁੱਥ A2DP ਕੋਡੇਕ ਨਮੂਨਾ ਦਰ ਚੁਣੋ"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ਪ੍ਰਤੀ ਨਮੂਨਾ ਬਲੂਟੁੱਥ ਔਡੀਓ ਬਿੱਟ"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"ਪ੍ਰਤੀ ਨਮੂਨਾ ਤਰਜੀਹੀ ਬਲੂਟੁੱਥ A2DP ਕੋਡੇਕ ਬਿੱਟ ਚੁਣੋ"</string>
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"ਪ੍ਰਤੀ ਨਮੂਨਾ ਬਲੂਟੁੱਥ ਔਡੀਓ ਬਿਟਾਂ"</string>
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"ਪ੍ਰਤੀ ਨਮੂਨਾ ਤਰਜੀਹੀ ਬਲੂਟੁੱਥ A2DP ਕੋਡੇਕ ਬਿਟਾਂ ਚੁਣੋ"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"ਬਲੂਟੁੱਥ ਔਡੀਓ ਚੈਨਲ ਮੋਡ"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"ਤਰਜੀਹੀ ਬਲੂਟੁੱਥ A2DP ਕੋਡੇਕ ਚੈਨਲ ਮੋਡ ਚੁਣੋ"</string>
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"ਬਲੂਟੁੱਥ ਔਡੀਓ LDAC ਪਲੇਬੈਕ ਗੁਣਵੱਤਾ"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/arrays.xml b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
index d17701e..7332f8a 100644
--- a/packages/SettingsLib/res/values-pt-rPT/arrays.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/arrays.xml
@@ -100,12 +100,12 @@
   </string-array>
   <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
     <item msgid="13423709606339855">"Predefinição"</item>
-    <item msgid="4106832974775067314">"Monocromático"</item>
+    <item msgid="4106832974775067314">"Mono"</item>
     <item msgid="5571632958424639155">"Estéreo"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_channel_mode_summaries">
     <item msgid="8128478683963250130">"Predefinição"</item>
-    <item msgid="8900559293912978337">"Monocromático"</item>
+    <item msgid="8900559293912978337">"Mono"</item>
     <item msgid="8883739882299884241">"Estéreo"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index a66ead0..c519b61 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -172,8 +172,8 @@
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Desativar volume absoluto"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Codec de áudio Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Selecionar Codec A2DP Bluetooth preferido"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Frequência de amostragem de áudio Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selecionar Frequência de amostragem de codec A2DP Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Taxa de amostragem de áudio Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Selecionar Taxa de amostragem de codec A2DP Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Bits por amostra de áudio Bluetooth"</string>
     <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Selecionar Bits por amostra de codec A2DP Bluetooth preferido"</string>
     <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Modo de canal áudio Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-sk/arrays.xml b/packages/SettingsLib/res/values-sk/arrays.xml
index 66fabb2..91b0351 100644
--- a/packages/SettingsLib/res/values-sk/arrays.xml
+++ b/packages/SettingsLib/res/values-sk/arrays.xml
@@ -109,14 +109,14 @@
     <item msgid="8883739882299884241">"Stereo"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"Preferovanie kvality zvuku (990/909 kb/s)"</item>
+    <item msgid="2944889121850394020">"Preferovaná kvalita zvuku (990/909 kb/s)"</item>
     <item msgid="138837449700903545">"Štandardné (660/606 kb/s)"</item>
-    <item msgid="4777177307869441982">"Preferovanie pripojenia (330/303 kb/s)"</item>
+    <item msgid="4777177307869441982">"Preferované pripojenie (330/303 kb/s)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"Preferovanie kvality zvuku (990/909 kb/s)"</item>
+    <item msgid="172302906231378902">"Preferovaná kvalita zvuku (990/909 kb/s)"</item>
     <item msgid="9091111147684472529">"Štandardné (660/606 kb/s)"</item>
-    <item msgid="3367904477834831032">"Preferovanie pripojenia (330/303 kb/s)"</item>
+    <item msgid="3367904477834831032">"Preferované pripojenie (330/303 kb/s)"</item>
   </string-array>
   <string-array name="select_logd_size_titles">
     <item msgid="8665206199209698501">"Vypnuté"</item>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index 563283b..bd1b71a 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -171,15 +171,15 @@
     <string name="mobile_data_always_on" msgid="7745605759775320362">"Data ya kifaa cha mkononi inatumika kila wakati"</string>
     <string name="bluetooth_disable_absolute_volume" msgid="2660673801947898809">"Zima sauti kamili"</string>
     <string name="bluetooth_select_a2dp_codec_type" msgid="90597356942154882">"Kodeki ya Sauti ya Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Chagua Kodeki Unayopendelea ya A2DP ya Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_type_dialog_title" msgid="6470824182074383881">"Chagua Kodeki Unayopendelea ya Bluetooth A2DP"</string>
     <string name="bluetooth_select_a2dp_codec_sample_rate" msgid="4788245703824623062">"Kiwango cha Sampuli ya Sauti ya Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Chagua Kiwango Unachopendelea cha Sampuli ya Kodeki ya A2DP ya Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title" msgid="4263851572248033749">"Chagua Kiwango Unachopendelea cha Sampuli ya Kodeki ya Bluetooth A2DP"</string>
     <string name="bluetooth_select_a2dp_codec_bits_per_sample" msgid="2099645202720164141">"Biti za Sauti ya Bluetooth kwa Kila Sampuli"</string>
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Chagua Biti za Kodeki ya A2DP ya Bluetooth Unazopendelea kwa Kila Sampuli"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Hali ya Kituo cha Sauti ya Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Chagua Hali ya Kituo cha Kodeki ya A2DP ya Bluetooth Unayopendelea"</string>
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title" msgid="2096170505745650345">"Chagua Biti za Kodeki ya Bluetooth A2DP Unazopendelea kwa Kila Sampuli"</string>
+    <string name="bluetooth_select_a2dp_codec_channel_mode" msgid="884855779449390540">"Hali ya Mkondo wa Sauti ya Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title" msgid="4073812880900816325">"Chagua Hali ya Mkondo wa Kodeki ya Bluetooth A2DP Unayopendelea"</string>
     <string name="bluetooth_select_a2dp_codec_ldac_playback_quality" msgid="4846872213548295632">"Ubora wa Kucheza LDAC ya Sauti ya Bluetooth"</string>
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Chagua Ubora Unaopendelea wa Kucheza LDAC ya Kodeki ya A2DP ya Bluetooth"</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title" msgid="3940973633342423717">"Chagua Ubora Unaopendelea wa Kucheza LDAC ya Kodeki ya Bluetooth A2DP"</string>
     <string name="wifi_display_certification_summary" msgid="1155182309166746973">"Onyesha chaguo za cheti cha kuonyesha pasiwaya"</string>
     <string name="wifi_verbose_logging_summary" msgid="6615071616111731958">"Ongeza hatua ya uwekaji kumbukumbu ya Wi-Fi, onyesha kwa kila SSID RSSI kwenye Kichukuzi cha Wi-Fi"</string>
     <string name="wifi_aggressive_handover_summary" msgid="6328455667642570371">"Ikiwashwa, Wifi itakabidhi kwa hima muunganisho wa data kwa mtandao wa Simu za Mkononi, mawimbi ya Wifi yanapokuwa hafifu"</string>
diff --git a/packages/SettingsLib/res/values-vi/arrays.xml b/packages/SettingsLib/res/values-vi/arrays.xml
index e7dbd4e..3f6f729 100644
--- a/packages/SettingsLib/res/values-vi/arrays.xml
+++ b/packages/SettingsLib/res/values-vi/arrays.xml
@@ -109,12 +109,12 @@
     <item msgid="8883739882299884241">"Âm thanh nổi"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-    <item msgid="2944889121850394020">"C.lượng â.thanh ưu tiên (990kbps/909kbps)"</item>
+    <item msgid="2944889121850394020">"Ưu tiên chất lượng (990kbps/909kbps)"</item>
     <item msgid="138837449700903545">"Tiêu chuẩn (660kb/giây/606kb/giây)"</item>
     <item msgid="4777177307869441982">"Kết nối được ưu tiên (330kb/giây/303kb/giây)"</item>
   </string-array>
   <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries">
-    <item msgid="172302906231378902">"C.lượng â.thanh ưu tiên (990kbps/909kbps)"</item>
+    <item msgid="172302906231378902">"Ưu tiên chất lượng (990kbps/909kbps)"</item>
     <item msgid="9091111147684472529">"Tiêu chuẩn (660kb/giây/606kb/giây)"</item>
     <item msgid="3367904477834831032">"Kết nối được ưu tiên (330kb/giây/303kb/giây)"</item>
   </string-array>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 5c00985..cfb990e 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -105,10 +105,10 @@
 
     <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40] -->
     <string-array name="bluetooth_a2dp_codec_titles">
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>SBC</item>
         <item>aptX</item>
-        <item>aptX-HD</item>
+        <item>aptX HD</item>
         <item>LDAC</item>
     </string-array>
 
@@ -123,16 +123,16 @@
 
     <!-- Summaries for Bluetooth Audio Codec selection preference. [CHAR LIMIT=40]-->
     <string-array name="bluetooth_a2dp_codec_summaries" >
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>SBC</item>
         <item>aptX</item>
-        <item>aptX-HD</item>
+        <item>aptX HD</item>
         <item>LDAC</item>
     </string-array>
 
     <!-- Titles for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40] -->
     <string-array name="bluetooth_a2dp_codec_sample_rate_titles">
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>44.1 kHz</item>
         <item>48.0 kHz</item>
         <item>88.2 kHz</item>
@@ -150,7 +150,7 @@
 
     <!-- Summaries for Bluetooth Audio Codec Sample Rate selection preference. [CHAR LIMIT=40]-->
     <string-array name="bluetooth_a2dp_codec_sample_rate_summaries" >
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>44.1 kHz</item>
         <item>48.0 kHz</item>
         <item>88.2 kHz</item>
@@ -159,7 +159,7 @@
 
     <!-- Titles for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40] -->
     <string-array name="bluetooth_a2dp_codec_bits_per_sample_titles">
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>16 bits/sample</item>
         <item>24 bits/sample</item>
         <item>32 bits/sample</item>
@@ -175,7 +175,7 @@
 
     <!-- Summaries for Bluetooth Audio Codec Bits Per Sample selection preference. [CHAR LIMIT=40]-->
     <string-array name="bluetooth_a2dp_codec_bits_per_sample_summaries" >
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>16 bits/sample</item>
         <item>24 bits/sample</item>
         <item>32 bits/sample</item>
@@ -183,7 +183,7 @@
 
     <!-- Titles for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40] -->
     <string-array name="bluetooth_a2dp_codec_channel_mode_titles">
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>Mono</item>
         <item>Stereo</item>
     </string-array>
@@ -197,16 +197,16 @@
 
     <!-- Summaries for Bluetooth Audio Codec Channel Mode selection preference. [CHAR LIMIT=40]-->
     <string-array name="bluetooth_a2dp_codec_channel_mode_summaries" >
-        <item>Default</item>
+        <item>Use System Selection (Default)</item>
         <item>Mono</item>
         <item>Stereo</item>
     </string-array>
 
-    <!-- Titles for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=40] -->
+    <!-- Titles for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=70] -->
     <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_titles">
-        <item>Sound quality preferred (990kbps/909kbps)</item>
-        <item>Standard (660kbps/606kbps)</item>
-        <item>Connection preferred (330kbps/303kbps)</item>
+        <item>Optimize for Audio Quality (990kbps/909kbps)</item>
+        <item>Balanced Audio And Connection Quality (660kbps/606kbps)</item>
+        <item>Optimize for Connection Quality (330kbps/303kbps)</item>
     </string-array>
 
     <!-- Values for Bluetooth Audio Codec LDAC Playback Quaility selection preference. -->
@@ -216,11 +216,11 @@
         <item>1002</item>
     </string-array>
 
-    <!-- Summaries for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=40]-->
+    <!-- Summaries for Bluetooth Audio Codec LDAC Playback Quality selection preference. [CHAR LIMIT=70]-->
     <string-array name="bluetooth_a2dp_codec_ldac_playback_quality_summaries" >
-        <item>Sound quality preferred (990kbps/909kbps)</item>
-        <item>Standard (660kbps/606kbps)</item>
-        <item>Connection preferred (330kbps/303kbps)</item>
+        <item>Optimize for Audio Quality</item>
+        <item>Balanced Audio And Connection Quality</item>
+        <item>Optimize for Connection Quality</item>
     </string-array>
 
     <!-- Titles for logd limit size selection preference. [CHAR LIMIT=14] -->
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 93bd5dc..a1b2bdf 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -430,28 +430,31 @@
 
     <!-- UI debug setting: Select Bluetooth Audio Codec -->
     <string name="bluetooth_select_a2dp_codec_type">Bluetooth Audio Codec</string>
-    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec -->
-    <string name="bluetooth_select_a2dp_codec_type_dialog_title">Select Preferred Bluetooth A2DP Codec</string>
+    <!-- UI debug setting: Select Bluetooth Audio Codec -->
+    <string name="bluetooth_select_a2dp_codec_type_dialog_title">Select Bluetooth Audio Codec</string>
 
     <!-- UI debug setting: Select Bluetooth Audio Sample Rate -->
     <string name="bluetooth_select_a2dp_codec_sample_rate">Bluetooth Audio Sample Rate</string>
-    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Sample Rate -->
-    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Select Preferred Bluetooth A2DP Codec Sample Rate</string>
+    <!-- UI debug setting: Select Bluetooth Audio Codec: Sample Rate -->
+    <string name="bluetooth_select_a2dp_codec_sample_rate_dialog_title">Select Bluetooth Audio Codec:\u000ASample Rate</string>
 
     <!-- UI debug setting: Select Bluetooth Audio Bits Per Sample -->
     <string name="bluetooth_select_a2dp_codec_bits_per_sample">Bluetooth Audio Bits Per Sample</string>
-    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Bits Per Sample -->
-    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Select Preferred Bluetooth A2DP Codec Bits Per Sample</string>
+    <!-- UI debug setting: Select Bluetooth Audio Codec: Bits Per Sample -->
+    <string name="bluetooth_select_a2dp_codec_bits_per_sample_dialog_title">Select Bluetooth Audio Codec:\u000ABits Per Sample</string>
 
     <!-- UI debug setting: Select Bluetooth Audio Channel Mode -->
     <string name="bluetooth_select_a2dp_codec_channel_mode">Bluetooth Audio Channel Mode</string>
-    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec Channel Mode -->
-    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Select Preferred Bluetooth A2DP Codec Channel Mode</string>
+    <!-- UI debug setting: Select Bluetooth Audio Codec: Channel Mode -->
+    <string name="bluetooth_select_a2dp_codec_channel_mode_dialog_title">Select Bluetooth Audio Codec:\u000AChannel Mode</string>
 
     <!-- UI debug setting: Select Bluetooth Audio LDAC Playback Quality -->
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality">Bluetooth Audio LDAC Playback Quality</string>
-    <!-- UI debug setting: Select Preferred Bluetooth A2DP Codec LDAC Playback Quality -->
-    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Select Preferred Bluetooth A2DP Codec LDAC Playback Quality</string>
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality">Bluetooth Audio LDAC Codec: Playback Quality</string>
+    <!-- UI debug setting: Select Bluetooth Audio LDAC Codec: LDAC Playback Quality -->
+    <string name="bluetooth_select_a2dp_codec_ldac_playback_quality_dialog_title">Select Bluetooth Audio LDAC Codec:\u000APlayback Quality</string>
+
+    <!-- [CHAR LIMIT=NONE] Label for displaying Bluetooth Audio Codec Parameters while streaming -->
+    <string name="bluetooth_select_a2dp_codec_streaming_label">Streaming: <xliff:g id="streaming_parameter">%1$s</xliff:g></string>
 
     <!-- setting Checkbox summary whether to show options for wireless display certification  -->
     <string name="wifi_display_certification_summary">Show options for wireless display certification</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
index fcff305..9bb3c36 100644
--- a/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/accessibility/AccessibilityUtils.java
@@ -28,6 +28,8 @@
 import android.util.ArraySet;
 import android.view.accessibility.AccessibilityManager;
 
+import com.android.internal.R;
+
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
@@ -147,6 +149,26 @@
                 enabledServicesBuilder.toString(), userId);
     }
 
+    /**
+     * Get the name of the service that should be toggled by the accessibility shortcut. Use
+     * an OEM-configurable default if the setting has never been set.
+     *
+     * @param context A valid context
+     * @param userId The user whose settings should be checked
+     *
+     * @return The component name, flattened to a string, of the target service.
+     */
+    public static String getShortcutTargetServiceComponentNameString(
+            Context context, int userId) {
+        final String currentShortcutServiceId = Settings.Secure.getStringForUser(
+                context.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+                userId);
+        if (currentShortcutServiceId != null) {
+            return currentShortcutServiceId;
+        }
+        return context.getString(R.string.config_defaultAccessibilityService);
+    }
+
     private static Set<ComponentName> getInstalledServices(Context context) {
         final Set<ComponentName> installedServices = new HashSet<>();
         installedServices.clear();
diff --git a/packages/SettingsProvider/Android.mk b/packages/SettingsProvider/Android.mk
index 710214c..069e83a 100644
--- a/packages/SettingsProvider/Android.mk
+++ b/packages/SettingsProvider/Android.mk
@@ -7,6 +7,7 @@
     src/com/android/providers/settings/EventLogTags.logtags
 
 LOCAL_JAVA_LIBRARIES := telephony-common ims-common
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 LOCAL_PACKAGE_NAME := SettingsProvider
 LOCAL_CERTIFICATE := platform
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 3e62158..058e38a 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -61,6 +61,7 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.ByteStringUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -76,9 +77,13 @@
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
 import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
 import java.security.SecureRandom;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -162,6 +167,7 @@
     public static final int SETTINGS_TYPE_GLOBAL = 0;
     public static final int SETTINGS_TYPE_SYSTEM = 1;
     public static final int SETTINGS_TYPE_SECURE = 2;
+    public static final int SETTINGS_TYPE_SSAID = 3;
 
     public static final int SETTINGS_TYPE_MASK = 0xF0000000;
     public static final int SETTINGS_TYPE_SHIFT = 28;
@@ -249,6 +255,9 @@
             case SETTINGS_TYPE_SYSTEM: {
                 return "SETTINGS_SYSTEM";
             }
+            case SETTINGS_TYPE_SSAID: {
+                return "SETTINGS_SSAID";
+            }
             default: {
                 return "UNKNOWN";
             }
@@ -704,6 +713,13 @@
                             UserHandle.getUserId(uid));
                 }
             }
+
+            @Override
+            public void onUidRemoved(int uid) {
+                synchronized (mLock) {
+                    mSettingsRegistry.onUidRemovedLocked(uid);
+                }
+            }
         };
 
         // package changes
@@ -957,8 +973,15 @@
                     continue;
                 }
 
-                Setting setting = mSettingsRegistry.getSettingLocked(
-                        SETTINGS_TYPE_SECURE, owningUserId, name);
+                // As of Android O (API 24), the SSAID is read from an app-specific entry in table
+                // SETTINGS_FILE_SSAID, unless accessed by a system process.
+                final Setting setting;
+                if (isNewSsaidSetting(name)) {
+                    setting = getSsaidSettingLocked(owningUserId);
+                } else {
+                    setting = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SECURE, owningUserId,
+                            name);
+                }
                 appendSettingToCursor(result, setting);
             }
 
@@ -986,11 +1009,43 @@
 
         // Get the value.
         synchronized (mLock) {
+            // As of Android O (API 24), the SSAID is read from an app-specific entry in table
+            // SETTINGS_FILE_SSAID, unless accessed by a system process.
+            if (isNewSsaidSetting(name)) {
+                return getSsaidSettingLocked(owningUserId);
+            }
+
             return mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SECURE,
                     owningUserId, name);
         }
     }
 
+    private boolean isNewSsaidSetting(String name) {
+        return Settings.Secure.ANDROID_ID.equals(name)
+                && UserHandle.getAppId(Binder.getCallingUid()) >= Process.FIRST_APPLICATION_UID;
+    }
+
+    private Setting getSsaidSettingLocked(int owningUserId) {
+        // Get uid of caller (key) used to store ssaid value
+        String name = Integer.toString(
+                UserHandle.getUid(owningUserId, UserHandle.getAppId(Binder.getCallingUid())));
+
+        if (DEBUG) {
+            Slog.v(LOG_TAG, "getSsaidSettingLocked(" + name + "," + owningUserId + ")");
+        }
+
+        // Retrieve the ssaid from the table if present.
+        final Setting ssaid = mSettingsRegistry.getSettingLocked(SETTINGS_TYPE_SSAID, owningUserId,
+                name);
+
+        // Lazy initialize ssaid if not yet present in ssaid table.
+        if (ssaid.isNull() || ssaid.getValue() == null) {
+            return mSettingsRegistry.generateSsaidLocked(getCallingPackage(), owningUserId);
+        }
+
+        return ssaid;
+    }
+
     private boolean insertSecureSetting(String name, String value, String tag,
             boolean makeDefault, int requestingUserId, boolean forceNotify) {
         if (DEBUG) {
@@ -1818,6 +1873,9 @@
         private static final String SETTINGS_FILE_GLOBAL = "settings_global.xml";
         private static final String SETTINGS_FILE_SYSTEM = "settings_system.xml";
         private static final String SETTINGS_FILE_SECURE = "settings_secure.xml";
+        private static final String SETTINGS_FILE_SSAID = "settings_ssaid.xml";
+
+        private static final String SSAID_USER_KEY = "userkey";
 
         private final SparseArray<SettingsState> mSettingsStates = new SparseArray<>();
 
@@ -1832,6 +1890,115 @@
             mGenerationRegistry = new GenerationRegistry(mLock);
             mBackupManager = new BackupManager(getContext());
             migrateAllLegacySettingsIfNeeded();
+            syncSsaidTableOnStart();
+        }
+
+        private void generateUserKeyLocked(int userId) {
+            // Generate a random key for each user used for creating a new ssaid.
+            final byte[] keyBytes = new byte[16];
+            final SecureRandom rand = new SecureRandom();
+            rand.nextBytes(keyBytes);
+
+            // Convert to string for storage in settings table.
+            final String userKey = ByteStringUtils.toString(keyBytes);
+
+            // Store the key in the ssaid table.
+            final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
+            final boolean success = ssaidSettings.insertSettingLocked(SSAID_USER_KEY, userKey, null,
+                    true, SettingsState.SYSTEM_PACKAGE_NAME);
+
+            if (!success) {
+                throw new IllegalStateException("Ssaid settings not accessible");
+            }
+        }
+
+        public Setting generateSsaidLocked(String packageName, int userId) {
+            final PackageInfo packageInfo;
+            try {
+                packageInfo = mPackageManager.getPackageInfo(packageName,
+                        PackageManager.GET_SIGNATURES, userId);
+            } catch (RemoteException e) {
+                throw new IllegalStateException("Package info doesn't exist");
+            }
+
+            // Read the user's key from the ssaid table.
+            Setting userKeySetting = getSettingLocked(SETTINGS_TYPE_SSAID, userId, SSAID_USER_KEY);
+            if (userKeySetting.isNull() || userKeySetting.getValue() == null) {
+                // Lazy initialize and store the user key.
+                generateUserKeyLocked(userId);
+                userKeySetting = getSettingLocked(SETTINGS_TYPE_SSAID, userId, SSAID_USER_KEY);
+                if (userKeySetting.isNull() || userKeySetting.getValue() == null) {
+                    throw new IllegalStateException("User key not accessible");
+                }
+            }
+            final String userKey = userKeySetting.getValue();
+
+            // Convert the user's key back to a byte array.
+            final byte[] keyBytes = ByteStringUtils.toByteArray(userKey);
+            if (keyBytes == null || keyBytes.length != 16) {
+                throw new IllegalStateException("User key invalid");
+            }
+
+            final MessageDigest md;
+            try {
+                // Hash package name and signature.
+                md = MessageDigest.getInstance("SHA-256");
+            } catch (NoSuchAlgorithmException e) {
+                throw new IllegalStateException("HmacSHA256 is not available");
+            }
+            md.update(keyBytes);
+            md.update(packageInfo.packageName.getBytes(StandardCharsets.UTF_8));
+            md.update(packageInfo.signatures[0].toByteArray());
+
+            // Convert result to a string for storage in settings table. Only want first 64 bits.
+            final String ssaid = ByteStringUtils.toString(md.digest()).substring(0, 16)
+                    .toLowerCase();
+
+            // Save the ssaid in the ssaid table.
+            final String uid = Integer.toString(packageInfo.applicationInfo.uid);
+            final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
+            final boolean success = ssaidSettings.insertSettingLocked(uid, ssaid, null, true,
+                    packageName);
+
+            if (!success) {
+                throw new IllegalStateException("Ssaid settings not accessible");
+            }
+
+            return getSettingLocked(SETTINGS_TYPE_SSAID, userId, uid);
+        }
+
+        public void syncSsaidTableOnStart() {
+            synchronized (mLock) {
+                // Verify that each user's packages and ssaid's are in sync.
+                for (UserInfo user : mUserManager.getUsers(true)) {
+                    // Get all uids for the user's packages.
+                    final List<PackageInfo> packages;
+                    try {
+                        packages = mPackageManager.getInstalledPackages(0, user.id).getList();
+                    } catch (RemoteException e) {
+                        throw new IllegalStateException("Package manager not available");
+                    }
+                    final Set<String> appUids = new HashSet<>();
+                    for (PackageInfo info : packages) {
+                        appUids.add(Integer.toString(info.applicationInfo.uid));
+                    }
+
+                    // Get all uids currently stored in the user's ssaid table.
+                    final Set<String> ssaidUids = new HashSet<>(
+                            getSettingsNamesLocked(SETTINGS_TYPE_SSAID, user.id));
+                    ssaidUids.remove(SSAID_USER_KEY);
+
+                    // Perform a set difference for the appUids and ssaidUids.
+                    ssaidUids.removeAll(appUids);
+
+                    // If there are ssaidUids left over they need to be removed from the table.
+                    final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID,
+                            user.id);
+                    for (String uid : ssaidUids) {
+                        ssaidSettings.deleteSettingLocked(uid);
+                    }
+                }
+            }
         }
 
         public List<String> getSettingsNamesLocked(int type, int userId) {
@@ -1884,6 +2051,10 @@
             final int systemKey = makeKey(SETTINGS_TYPE_SYSTEM, userId);
             ensureSettingsStateLocked(systemKey);
 
+            // Ensure secure settings loaded.
+            final int ssaidKey = makeKey(SETTINGS_TYPE_SSAID, userId);
+            ensureSettingsStateLocked(ssaidKey);
+
             // Upgrade the settings to the latest version.
             UpgradeController upgrader = new UpgradeController(userId);
             upgrader.upgradeIfNeededLocked();
@@ -1936,6 +2107,23 @@
                 }
             }
 
+            // Nuke ssaid settings.
+            final int ssaidKey = makeKey(SETTINGS_TYPE_SSAID, userId);
+            final SettingsState ssaidSettingsState = mSettingsStates.get(ssaidKey);
+            if (ssaidSettingsState != null) {
+                if (permanently) {
+                    mSettingsStates.remove(ssaidKey);
+                    ssaidSettingsState.destroyLocked(null);
+                } else {
+                    ssaidSettingsState.destroyLocked(new Runnable() {
+                        @Override
+                        public void run() {
+                            mSettingsStates.remove(ssaidKey);
+                        }
+                    });
+                }
+            }
+
             // Nuke generation tracking data
             mGenerationRegistry.onUserRemoved(userId);
         }
@@ -1977,8 +2165,10 @@
 
             SettingsState settingsState = peekSettingsStateLocked(key);
             if (settingsState == null) {
-                return null;
+                return settingsState.getNullSetting();
             }
+
+            // getSettingLocked will return non-null result
             return settingsState.getSettingLocked(name);
         }
 
@@ -2079,6 +2269,12 @@
             }
         }
 
+        public void onUidRemovedLocked(int uid) {
+            final SettingsState ssaidSettings = getSettingsLocked(SETTINGS_TYPE_SSAID,
+                    UserHandle.getUserId(uid));
+            ssaidSettings.deleteSettingLocked(Integer.toString(uid));
+        }
+
         private SettingsState peekSettingsStateLocked(int key) {
             SettingsState settingsState = mSettingsStates.get(key);
             if (settingsState != null) {
@@ -2300,6 +2496,10 @@
             return getTypeFromKey(key) == SETTINGS_TYPE_SECURE;
         }
 
+        private boolean isSsaidSettingsKey(int key) {
+            return getTypeFromKey(key) == SETTINGS_TYPE_SSAID;
+        }
+
         private File getSettingsFile(int key) {
             if (isGlobalSettingsKey(key)) {
                 final int userId = getUserIdFromKey(key);
@@ -2313,6 +2513,10 @@
                 final int userId = getUserIdFromKey(key);
                 return new File(Environment.getUserSystemDirectory(userId),
                         SETTINGS_FILE_SECURE);
+            } else if (isSsaidSettingsKey(key)) {
+                final int userId = getUserIdFromKey(key);
+                return new File(Environment.getUserSystemDirectory(userId),
+                        SETTINGS_FILE_SSAID);
             } else {
                 throw new IllegalArgumentException("Invalid settings key:" + key);
             }
@@ -2336,7 +2540,8 @@
         private int getMaxBytesPerPackageForType(int type) {
             switch (type) {
                 case SETTINGS_TYPE_GLOBAL:
-                case SETTINGS_TYPE_SECURE: {
+                case SETTINGS_TYPE_SECURE:
+                case SETTINGS_TYPE_SSAID: {
                     return SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED;
                 }
 
@@ -2374,7 +2579,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 136;
+            private static final int SETTINGS_VERSION = 137;
 
             private final int mUserId;
 
@@ -2447,6 +2652,10 @@
                 return getSettingsLocked(SETTINGS_TYPE_SECURE, userId);
             }
 
+            private SettingsState getSsaidSettingsLocked(int userId) {
+                return getSettingsLocked(SETTINGS_TYPE_SSAID, userId);
+            }
+
             private SettingsState getSystemSettingsLocked(int userId) {
                 return getSettingsLocked(SETTINGS_TYPE_SYSTEM, userId);
             }
@@ -2776,6 +2985,48 @@
                     currentVersion = 136;
                 }
 
+                if (currentVersion == 136) {
+                    // Version 136: Store legacy SSAID for all apps currently installed on the
+                    // device as first step in migrating SSAID to be unique per application.
+
+                    final boolean isUpgrade;
+                    try {
+                        isUpgrade = mPackageManager.isUpgrade();
+                    } catch (RemoteException e) {
+                        throw new IllegalStateException("Package manager not available");
+                    }
+                    // Only retain legacy ssaid if the device is performing an OTA. After wiping
+                    // user data or first boot on a new device should use new ssaid generation.
+                    if (isUpgrade) {
+                        // Retrieve the legacy ssaid from the secure settings table.
+                        final String legacySsaid = getSettingLocked(SETTINGS_TYPE_SECURE, userId,
+                                Settings.Secure.ANDROID_ID).getValue();
+
+                        // Fill each uid with the legacy ssaid to be backwards compatible.
+                        final List<PackageInfo> packages;
+                        try {
+                            packages = mPackageManager.getInstalledPackages(0, userId).getList();
+                        } catch (RemoteException e) {
+                            throw new IllegalStateException("Package manager not available");
+                        }
+
+                        final SettingsState ssaidSettings = getSsaidSettingsLocked(userId);
+                        for (PackageInfo info : packages) {
+                            // Check if the UID already has an entry in the table.
+                            final String uid = Integer.toString(info.applicationInfo.uid);
+                            final Setting ssaid = ssaidSettings.getSettingLocked(uid);
+
+                            if (ssaid.isNull() || ssaid.getValue() == null) {
+                                // Android Id doesn't exist for this package so create it.
+                                ssaidSettings.insertSettingLocked(uid, legacySsaid, null, true,
+                                        info.packageName);
+                            }
+                        }
+                    }
+
+                    currentVersion = 137;
+                }
+
                 if (currentVersion != newVersion) {
                     Slog.wtf("SettingsProvider", "warning: upgrading settings database to version "
                             + newVersion + " left it at "
diff --git a/packages/SettingsProvider/test/Android.mk b/packages/SettingsProvider/test/Android.mk
index 918410e..d039f03 100644
--- a/packages/SettingsProvider/test/Android.mk
+++ b/packages/SettingsProvider/test/Android.mk
@@ -9,7 +9,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files) \
     ../src/com/android/providers/settings/SettingsState.java
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test legacy-android-test
 
 LOCAL_PACKAGE_NAME := SettingsProviderTest
 
@@ -17,4 +17,4 @@
 
 LOCAL_CERTIFICATE := platform
 
-include $(BUILD_PACKAGE)
\ No newline at end of file
+include $(BUILD_PACKAGE)
diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk
index 0424eb0..acd552d 100644
--- a/packages/Shell/tests/Android.mk
+++ b/packages/Shell/tests/Android.mk
@@ -12,6 +12,8 @@
     android-support-test \
     mockito-target-minus-junit4 \
     ub-uiautomator \
+    junit \
+    legacy-android-test \
 
 LOCAL_PACKAGE_NAME := ShellTests
 LOCAL_INSTRUMENTATION_FOR := Shell
diff --git a/packages/SystemUI/res/drawable/ic_qs_nfc_disabled.xml b/packages/SystemUI/res/drawable/ic_qs_nfc_disabled.xml
new file mode 100644
index 0000000..558f3d0
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_nfc_disabled.xml
@@ -0,0 +1,31 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M4 20h16V4H4v16z" />
+    <path
+        android:fillColor="#4DFFFFFF"
+        android:pathData="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1 .9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0
+18H4V4h16v16zM18 6h-5c-1.1 0-2 .9-2 2v2.28c-.6 .35 -1 .98-1 1.72 0 1.1 .9 2 2
+2s2-.9 2-2c0-.74-.4-1.38-1-1.72V8h3v8H8V8h2V6H6v12h12V6z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_nfc_enabled.xml b/packages/SystemUI/res/drawable/ic_qs_nfc_enabled.xml
new file mode 100644
index 0000000..becb18a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_nfc_enabled.xml
@@ -0,0 +1,31 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:pathData="M4 20h16V4H4v16z" />
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1 .9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0
+18H4V4h16v16zM18 6h-5c-1.1 0-2 .9-2 2v2.28c-.6 .35 -1 .98-1 1.72 0 1.1 .9 2 2
+2s2-.9 2-2c0-.74-.4-1.38-1-1.72V8h3v8H8V8h2V6H6v12h12V6z" />
+    <path
+        android:pathData="M0 0h24v24H0z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml b/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
new file mode 100644
index 0000000..a85beb8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/recents_grid_task_view_focus_frame_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+  <solid android:color="#61FFFFFF" />
+  <corners android:radius="8dp"/>
+</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/navigation_bar_window.xml b/packages/SystemUI/res/layout/navigation_bar_window.xml
new file mode 100644
index 0000000..051bf3a
--- /dev/null
+++ b/packages/SystemUI/res/layout/navigation_bar_window.xml
@@ -0,0 +1,26 @@
+<?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.
+*/
+-->
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:systemui="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/navigation_bar_frame"
+    android:layout_height="match_parent"
+    android:layout_width="match_parent">
+
+</FrameLayout>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index aa6c620..2d10668 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Sluitskerm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Instellings"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Oorsig."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Werksluitskerm"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Maak toe"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi afgeskakel."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Vou uit"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Vou in"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skerm is vasgespeld"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Terug en Oorsig om dit te ontspeld."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Dit hou dit in sig totdat jy dit ontspeld. Raak en hou Oorsig om dit te ontspeld."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Het dit"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nee, dankie"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Versteek <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Aan"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Af"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Met kragkennisgewingkontroles kan jy \'n belangrikheidvlak van 0 tot 5 vir \'n program se kennisgewings stel. \n\n"<b>"Vlak 5"</b>" \n- Wys aan die bokant van die kennisgewinglys \n- Laat volskermonderbreking toe \n- Wys altyd opspringkennisgewings \n\n"<b>"Vlak 4"</b>" \n- Verhoed volskermonderbreking \n- Wys altyd opspringkennisgewings \n\n"<b>"Vlak 3"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n\n"<b>"Vlak 2"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n- Moet nooit \'n klank maak of vibreer nie \n\n"<b>"Vlak 1"</b>" \n- Verhoed volskermonderbreking \n- Verhoed opspringkennisgewings \n- Moet nooit \'n klank maak of vibreer nie \n- Versteek van sluitskerm en statusbalk \n- Wys aan die onderkant van die kennisgewinglys \n\n"<b>"Vlak 0"</b>" \n- Blokkeer alle kennisgewings van die program af"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Kennisgewings"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Jy sal nie meer hierdie kennisgewings kry nie."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-kennisgewings vir"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Laag"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Middelmatig"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Hoog"</string>
+    <string name="high_importance" msgid="730741630855788381">"Dringend"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Geen klank of visuele onderbreking nie"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Wys sonder klank"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Maak geluid"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Maak geluid en spring op op skerm"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
     <string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-kennisgewingkontroles"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 210647c..a45dd18 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ማያ ገጽ ቆልፍ።"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ቅንብሮች"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"አጠቃላይ እይታ።"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"የስራ ማያ ገጽ ቁልፍ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ዝጋ"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>።"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi ጠፍቷል።"</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"አስፋ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ሰብስብ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ማያ ገጽ ተሰክቷል"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል ተመለስ እና አጠቃላይ ዕይታ የሚለውን ይጫኑ እና ይያዙ።"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ይሄ እስኪነቅሉት ድረስ በእይታ ውስጥ ያስቀምጠዋል። ለመንቀል አጠቃላይ ዕይታ ተጭነው ይያዙ።"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ገባኝ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"አይ፣ አመሰግናለሁ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ይደበቅ?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"በርቷል"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ጠፍቷል"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"በኃይል ማሳወቂያ መቆጣጠሪያዎች አማካኝነት የአንድ መተግበሪያ ማሳወቂያዎች የአስፈላጊነት ደረጃ ከ0 እስከ 5 ድረስ ማዘጋጀት ይችላሉ። \n\n"<b>"ደረጃ 5"</b>" \n- በማሳወቂያ ዝርዝሩ አናት ላይ አሳይ \n- የሙሉ ማያ ገጽ ማቋረጥን ፍቀድ \n- ሁልጊዜ አጮልቀው ይመልከቱ \n\n"<b>"ደረጃ 4"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ከልክል \n- ሁልጊዜ አጮልቀው ይመልከቱ \n\n"<b>"ደረጃ 3"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ከልክል \n- በፍጹም አጮልቀው አይምልከቱ \n\n"<b>"ደረጃ 2"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ይከልክሉ \n- በፍጹም አጮልቀው አይመልከቱ \n- ድምፅ እና ንዝረትን በፍጹም አይኑር \n\n"<b>"ደረጃ 1"</b>" \n- የሙሉ ማያ ገጽ ማቋረጥን ይከልክሉ \n- በፍጹም አጮልቀው አይመልከቱ \n- ድምፅ ወይም ንዝረትን በፍጹም አያደርጉ \n- ከመቆለፊያ ገጽ እና የሁኔታ አሞሌ ይደብቁ \n- በማሳወቂያ ዝርዝር ግርጌ ላይ አሳይ \n\n"<b>"ደረጃ 0"</b>" \n- ሁሉንም የመተግበሪያው ማሳወቂያዎች ያግዱ"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"ማሳወቂያዎች"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"እነዚህን ማሳወቂያዎች ከእንግዲህ አያግኙዋቸውም።"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> ማሳወቂያዎች ለ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"ዝቅተኛ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"መካከለኛ"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ከፍተኛ"</string>
+    <string name="high_importance" msgid="730741630855788381">"አስቸኳይ"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ምንም ድምፅ ወይም የሚታይ ትርጉም የለም"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"በፀጥታ አሳይ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ድምፅ ፍጠር"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ድምፅ ፍጠር እና በማያ ገጽ ላይ ብቅ በል"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ተጨማሪ ቅንብሮች"</string>
     <string name="notification_done" msgid="5279426047273930175">"ተከናውኗል"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ማሳወቂያ ቁጥጥሮች"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index ed64c41..074f754 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"شاشة التأمين."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"الإعدادات"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"النظرة عامة."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"شاشة تأمين بيانات العمل"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"إغلاق"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"‏تم إيقاف Wifi."</string>
@@ -448,10 +447,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"توسيع"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"تصغير"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"تم تثبيت الشاشة"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار الزرين \"رجوع\" و\"نظرة عامة\" لإزالة التثبيت."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"يؤدي هذا إلى استمرار عرض الشاشة المُختارة إلى أن تتم إزالة تثبيتها. المس مع الاستمرار زر \"نظرة عامة\" لإزالة التثبيت."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"حسنًا"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"لا، شكرًا"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"هل تريد إخفاء <xliff:g id="TILE_LABEL">%1$s</xliff:g>؟"</string>
@@ -518,28 +515,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"تشغيل"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"إيقاف"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"باستخدام عناصر التحكم في إشعار التشغيل، يمكنك تعيين مستوى الأهمية من 0 إلى 5 لإشعارات التطبيق. \n\n"<b>"المستوى 5"</b>" \n- العرض أعلى قائمة الإشعارات \n- يسمح بمقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 4"</b>" \n- منع مقاطعة ملء الشاشة \n- الظهور الخاطف دائمًا \n\n"<b>"المستوى 3"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n\n"<b>"المستوى 2"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات واهتزاز \n\n"<b>"المستوى 1"</b>" \n- منع مقاطعة ملء الشاشة \n- عدم الظهور الخاطف أبدًا \n- عدم إصدار أصوات أو اهتزاز أبدًا \n- الإخفاء من شاشة التأمين وشريط الحالة \n- العرض أسفل قائمة الإشعارات \n\n"<b>"المستوى 0"</b>" \n- حظر جميع الإشعارات من التطبيق"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"الإشعارات"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"لن تتلقى هذه الإشعارات بعد الآن."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"إشعارات <xliff:g id="APP">%s</xliff:g> عن"</string>
+    <string name="min_importance" msgid="7559703098688382595">"منخفض الأهمية"</string>
+    <string name="low_importance" msgid="6891335321576225228">"متوسط الأهمية"</string>
+    <string name="default_importance" msgid="6400766013567512061">"أهمية عالية"</string>
+    <string name="high_importance" msgid="730741630855788381">"عاجل"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"من دون تنبيه صوتي أو مرئي"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"عرض بدون تنبيه صوتي"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"إصدار تنبيه صوتي"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"إصدار تنبيه صوتي والظهور بسرعة على الشاشة"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"المزيد من الإعدادات"</string>
     <string name="notification_done" msgid="5279426047273930175">"تم"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"عناصر التحكم في إشعارات <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 70e768c..7169d54 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Ekranı kilidləyin."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ayarlar"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"İcmal"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ekran kilidi"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Qapadın"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi deaktivdir."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Genişləndirin"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yığcamlaşdırın"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrana sancaq taxıldı"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri və İcmal düymələrinə basıb saxlayın."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Sancaq götürülənə qədər bu görünəcək. Sancağı götürmək üçün Geri düyməsinə basıb saxlayın."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Anladım!"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Yox, çox sağ olun"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlədilsin?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Aktiv"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Deaktiv"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Enerji bildiriş nəzarəti ilə, tətbiq bildirişləri üçün əhəmiyyət səviyyəsini 0-dan 5-ə kimi ayarlaya bilərsiniz. \n\n"<b>"Səviyyə 5"</b>" \n- Bildiriş siyahısının yuxarı hissəsində göstərin \n- Tam ekran kəsintisinə icazə verin \n- Hər zaman izləyin \n\n"<b>"Səviyyə 4"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Hər zaman izləyin \n\n"<b>"Level 3"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Heç vaxt izləməyin \n\n"<b>"Level 2"</b>" \n- Tam ekran kəsintisinin qarşısını alın \n- Heç vaxt izləməyin \n- Heç vaxt səsliyə və ya vibrasiyaya qoymayın \n\n"<b>"Səviyyə 1"</b>" \n- Prevent full screen interruption \n- Heç vaxt izləməyin \n- Heç vaxt səsliyə və ya vibrasiyaya qoymayın \n- Ekran kilidi və ya status panelindən gizlədin \n- Bildiriş siyahısının yuxarı hissəsində göstərin \n\n"<b>"Səviyyə 0"</b>" \n- Bütün bildirişləri tətbiqdən blok edin"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirişlər"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Bu bildirişlər daha sizə göndərilməyəcək."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> bildirişləri:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Az əhəmiyyətli"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Orta əhəmiyyətli"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Vacib"</string>
+    <string name="high_importance" msgid="730741630855788381">"Çox vacib"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Səs və ya vizual kəsintisiz"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Sakit səsli"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Səsli"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Səsli və ekranda pəncərə ilə"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Daha çox ayar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hazırdır"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildiriş nəzarəti"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 924ec8a..465bf70 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -186,8 +186,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Zaključani ekran."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Podešavanja"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pregled."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Zaključani ekran za posao"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zatvori"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi je isključen."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skupi"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran je zakačen"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Nazad i Pregled da biste ga otkačili."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Na ovaj način se ovo stalno prikazuje dok ga ne otkačite. Dodirnite i zadržite Pregled da biste ga otkačili."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Važi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li da sakrijete <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Uključeno"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Pomoću naprednih kontrola za obaveštenja možete da podesite nivo važnosti od 0. do 5. za obaveštenja aplikacije. \n\n"<b>"5. nivo"</b>" \n– Prikazuju se u vrhu liste obaveštenja \n- Dozvoli prekid režima celog ekrana \n– Uvek zaviruj \n\n"<b>"4. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Uvek zaviruj \n\n"<b>"3. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n\n"<b>"2. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n– Nikada ne proizvodi zvuk ili vibraciju \n\n"<b>"1. nivo"</b>" \n– Spreči prekid režima celog ekrana \n– Nikada ne zaviruj \n– Nikada ne proizvodi zvuk ili vibraciju \n– Sakrij na zaključanom ekranu i statusnoj traci \n– Prikazuju se u dnu liste obaveštenja \n\n"<b>"0. nivo"</b>" \n– Blokiraj sva obaveštenja iz aplikacije"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Obaveštenja"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Više nećete da dobijate ova obaveštenja."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Obaveštenja aplikacije <xliff:g id="APP">%s</xliff:g> za"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nisko"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Srednje"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Visoko"</string>
+    <string name="high_importance" msgid="730741630855788381">"Hitno"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez zvučnog signala ili vizuelnog obaveštenja"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Prikazuje se bez zvučnog signala"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emituje se zvučni signal"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emituje se zvučni signal i prikazuje se na ekranu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole obaveštenja za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 4b9cc5a..ee65b49 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Экран блакіроўкі."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Налады"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Агляд."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Экран блакіроўкі дзейнасці"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Закрыць"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi выключаны."</string>
@@ -446,10 +445,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Разгарнуць"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Згарнуць"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Экран замацаваны"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, краніце і ўтрымлівайце кнопкі \"Назад\" і \"Агляд\"."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Будзе паказвацца, пакуль не адмацуеце. Каб адмацаваць, краніце і ўтрымлівайце кнопку \"Агляд\"."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Зразумела"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, дзякуй"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Схаваць <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -516,28 +513,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Уключана"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Выключана"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"З дапамогай пашыранага кіравання апавяшчэннямі вы можаце задаваць узровень важнасці апавяшчэнняў праграмы ад 0 да 5. \n\n"<b>"Узровень 5"</b>" \n- Паказваць уверсе спіса апавяшчэнняў \n- Дазваляць перапыняць рэжым поўнага экрана \n- Заўсёды дазваляць кароткі паказ \n\n"<b>"Узровень 4"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Заўсёды дазваляць кароткі паказ \n\n"<b>"Узровень 3"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n\n"<b>"Узровень 2"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n- Ніколі не прайграваць гук і не вібрыраваць \n\n"<b>"Узровень 1"</b>" \n- Забараняць перапыняць рэжым поўнага экрана \n- Ніколі не дазваляць кароткі паказ \n- Ніколі не прайграваць гук і не вібрыраваць \n- Хаваць з экрана блакіроўкі і панэлі стану \n- Паказваць унізе спіса апавяшчэнняў \n\n"<b>"Узровень 0"</b>" \n- Блакіраваць усе апавяшчэнні ад праграмы"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Апавяшчэнні"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Вы больш не будзеце атрымліваць гэтыя апавяшчэнні."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Апавяшчэнні праграмы <xliff:g id="APP">%s</xliff:g> для"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Нізкая важнасць"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Сярэдняя важнасць"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Высокая важнасць"</string>
+    <string name="high_importance" msgid="730741630855788381">"Тэрміновае"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без гуку ці візуальнага перапынення"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Паказваць бязгучна"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Прайграваць гук"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Прайграваць гук і паказваць на экране"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Дадатковыя налады"</string>
     <string name="notification_done" msgid="5279426047273930175">"Гатова"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Элементы кантролю апавяшчэнняў <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index e8b4c16..bc07ed2 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Заключване на екрана."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Настройки"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Общ преглед."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Заключен екран на служебния профил"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Затваряне"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Функцията за Wi-Fi се изключи."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Разгъване"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Свиване"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екранът е фиксиран"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за връщане назад и този за общ преглед."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Екранът ще се показва, докато не го освободите с докосване и задържане на бутона за общ преглед."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Разбрах"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, благодаря"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Да се скрие ли „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Вкл."</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Изкл."</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"С помощта на контролите за известията можете да зададете ниво на важност от 0 до 5 за известията от дадено приложение. \n\n"<b>"Ниво 5"</b>" \n– Показване най-горе в списъка с известия. \n– Разрешаване на прекъсването на цял екран. \n– Известията винаги се показват мимолетно. \n\n"<b>"Ниво 4"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията винаги се показват мимолетно. \n\n"<b>"Ниво 3"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n\n"<b>"Ниво 2"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n– Без издаване на звуков сигнал и вибриране. \n\n"<b>"Ниво 1"</b>" \n– Предотвратяване на прекъсването на цял екран. \n– Известията никога не се показват мимолетно. \n– Без издаване на звуков сигнал и вибриране. \n– Скриване от заключения екран и лентата на състоянието. \n– Показване най-долу в списъка с известия. \n\n"<b>"Ниво 0"</b>" \n– Блокиране на всички известия от приложението."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Известия"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Вече няма да получавате тези известия."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Известия от <xliff:g id="APP">%s</xliff:g> за"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Малка"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Средна"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Голяма"</string>
+    <string name="high_importance" msgid="730741630855788381">"Неотложна"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без звук или визуално прекъсване"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Показване без звук"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Възпроизвеждане на звук"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Възпроизвеждане на звук и показване на изскачащ прозорец на екрана"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроли за известията от <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 2e543b1..65f74c8 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"লক স্ক্রীন।"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"সেটিংস"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"এক নজরে৷"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"কর্মস্থলের স্ক্রীন লক"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"বন্ধ করুন"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>।"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WiFi বন্ধ হয়েছে।"</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"প্রসারিত করুন"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"সঙ্কুচিত করুন"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"স্ক্রীন পিন করা হয়েছে"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ফিরুন এবং ওভারভিউ স্পর্শ করে ধরে থাকুন।"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"এটি আপনি আনপিন না করা পর্যন্ত এটিকে প্রদর্শিত করবে৷ আনপিন করতে ওভারভিউ স্পর্শ করে ধরে থাকুন৷"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"বুঝেছি"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"না থাক"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> লুকাবেন?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"চালু আছে"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"বন্ধ আছে"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"পাওয়ার বিজ্ঞপ্তির নিয়ন্ত্রণগুলি ব্যহবার করে, আপনি কোনো অ্যাপ্লিকেশানের বিজ্ঞপ্তির জন্য ০ থেকে ৫ পর্যন্ত একটি গুরুত্বের লেভেলকে সেট করতে পারবেন৷ \n\n"<b>"লেভেল ৫"</b>" \n- বিজ্ঞপ্তি তালিকার শীর্ষে দেখায় \n- পূর্ণ স্ক্রীনের বাধাকে অনুমতি দেয় \n- সর্বদা স্ক্রীনে উপস্থিত হয় \n\n"<b>"লেভেল ৪"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- সর্বদা স্ক্রীনে উপস্থিত হয় \n\n"<b>"লেভেল ৩"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- কখনই স্ক্রীনে উপস্থিত হয় না \n\n"<b>"লেভেল ২"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- কখনই স্ক্রীনে উপস্থিত হয় না \n- কখনই শব্দ এবং কম্পন করে না \n\n"<b>"লেভেল ১"</b>" \n- পূর্ণ স্ক্রীনের বাধাকে আটকায় \n- কখনই স্ক্রীনে উপস্থিত হয় না \n- কখনই শব্দ এবং কম্পন করে না \n- লক স্ক্রীন এবং স্থিতি দন্ড থেকে লুকায় \n- বিজ্ঞপ্তি তালিকার নীচের দিকে দেখায় \n\n"<b>"লেভেল ০"</b>" \n- অ্যাপ্লিকেশান থেকে সমস্ত বিজ্ঞপ্তিকে অবরূদ্ধ করে"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"বিজ্ঞপ্তি"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"আপনি আর এই বিজ্ঞপ্তিগুলি পাবেন না।"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"এর জন্য <xliff:g id="APP">%s</xliff:g> বিজ্ঞপ্তি"</string>
+    <string name="min_importance" msgid="7559703098688382595">"নিম্ন"</string>
+    <string name="low_importance" msgid="6891335321576225228">"মাঝারি"</string>
+    <string name="default_importance" msgid="6400766013567512061">"উচ্চ"</string>
+    <string name="high_importance" msgid="730741630855788381">"জরুরি"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"কোনো শব্দ বা ভিজ্যুয়াল বাধা নেই"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"নিঃশব্দে দেখান"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"শব্দ করে"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"শব্দ করে ও স্ক্রীনে ভেসে ওঠে"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"আরো সেটিংস"</string>
     <string name="notification_done" msgid="5279426047273930175">"সম্পন্ন"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> বিজ্ঞপ্তির নিয়ন্ত্রণগুলি"</string>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index f6dcf68..48fb824 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -186,8 +186,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Zaključan ekran."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Postavke"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pregled."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Zaključan ekran radnog profila"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zatvori"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi je isključen."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skupi"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran je prikačen"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ekran ostaje prikazan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Nazad."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran ostaje prikzan ovako dok ga ne otkačite. Da ga otkačite, dodirnite i držite dugme Pregled."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Jasno mi je"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -514,28 +511,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Uključeno"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Uz kontrolu obavještenja o napajanju, možete postaviti nivo značaja obavještenja iz aplikacije, i to od nivoa 0 do 5. \n\n"<b>"Nivo 5"</b>" \n- Prikaži na vrhu liste obavještenja \n- Dopusti prekid prikaza cijelog ekrana \n- Uvijek izviruj \n\n"<b>"Nvio 4"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Uvijek izviruj \n\n"<b>"Nivo 3"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikad ne izviruj \n\n"<b>"Nivo 2"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikad ne izviruj \n- Nikada ne puštaj zvuk ili vibraciju \n\n"<b>"Nivo 1"</b>" \n- Spriječi prekid prikaza cijelog ekrana \n- Nikada ne izviruj \n- Nikada ne puštaj zvuk ili vibraciju \n- Sakrij sa ekrana za zaključavanje i statusne trake \n- Prikaži na dnu liste obavještenja \n\n"<b>"Nivo 0"</b>" \n- Blokiraj sva obavještenja iz aplikacije"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Obavještenja"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Nećete više primati ova obavještenja."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Obavještenje aplikacije <xliff:g id="APP">%s</xliff:g> za"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Niska"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Srednja"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Visoka"</string>
+    <string name="high_importance" msgid="730741630855788381">"Hitno"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez ometanja zvukom ili prikazivanjem"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Prikaži bez zvuka"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Pusti zvuk"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Pusti zvuk i prikaži na ekranu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole <xliff:g id="APP_NAME">%1$s</xliff:g> obavještenja"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 93e9142..691bc6b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Pantalla de bloqueig"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Configuració"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Visió general"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Pantalla de bloqueig per a la feina"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Tanca"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"La xarxa Wi-Fi està desactivada."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Amplia"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Replega"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"La pantalla està fixada"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, toca i mantén premudes les opcions Enrere i Visió general."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Aquest element es continuarà mostrant fins que deixis de fixar-lo. Per fer-ho, toca i mantén premuda l\'opció Visió general."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"D\'acord"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gràcies"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vols amagar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Activat"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivat"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Amb els controls de notificació millorats, pots establir un nivell d\'importància d\'entre 0 i 5 per a les notificacions d\'una aplicació. \n\n"<b>"Nivell 5"</b>" \n- Mostra les notificacions a la part superior de la llista \n- Permet la interrupció de la pantalla completa \n- Permet sempre la previsualització \n\n"<b>"Nivell 4"</b>" \n- No permet la interrupció de la pantalla completa \n- Permet sempre la previsualització \n\n"<b>"Nivell 3"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n\n"<b>"Nivell 2"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n- Les notificacions no poden emetre sons ni vibracions \n\n"<b>"Nivell 1"</b>" \n- No permet la interrupció de la pantalla completa \n- No permet mai la previsualització \n- No activa mai el so ni la vibració \n- Amaga les notificacions de la pantalla de bloqueig i de la barra d\'estat \n- Mostra les notificacions a la part inferior de la llista \n\n"<b>"Nivell 0"</b>" \n- Bloqueja totes les notificacions de l\'aplicació"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificacions"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ja no rebràs aquestes notificacions."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificacions de l\'aplicació <xliff:g id="APP">%s</xliff:g> per a"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baixa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Mitjana"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgent"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Sense so ni interrupcions visuals"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Es mostren de manera silenciosa"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Amb so"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Amb so i amb una finestra emergent"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fet"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controls de notificació de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 350db19..2810d77 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Obrazovka uzamčení"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Nastavení"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Přehled"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Obrazovka uzamčení pracovního profilu"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zavřít"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Připojení Wi-Fi je vypnuto."</string>
@@ -446,10 +445,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozbalit"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sbalit"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Obrazovka je připnuta"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítek Zpět a Přehled."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Obsah bude připnut v zobrazení, dokud jej neuvolníte. Uvolníte jej stisknutím a podržením tlačítka Přehled."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Rozumím"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, děkuji"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skrýt <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -516,28 +513,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Zapnuto"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Vypnuto"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Rozšířené ovládací prvky oznámení umožňují nastavit úroveň důležitosti oznámení aplikace od 0 do 5. \n\n"<b>"Úroveň 5"</b>" \n– Zobrazit na začátku seznamu oznámení \n– Povolit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 4"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Vždy zobrazit náhled \n\n"<b>"Úroveň 3"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n\n"<b>"Úroveň 2"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat žádný zvukový signál ani nevibrovat \n\n"<b>"Úroveň 1"</b>" \n– Zabránit vyrušení na celou obrazovku \n– Nikdy nezobrazovat náhled \n– Nikdy nevydávat zvukový signál ani nevibrovat \n– Skrýt z obrazovky uzamčení a stavového řádku \n– Zobrazovat na konci seznamu oznámení \n\n"<b>";Úroveň 0"</b>" \n– Blokovat všechna oznámení z aplikace"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Oznámení"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Tato oznámení již nebudete dostávat."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Oznámení aplikace <xliff:g id="APP">%s</xliff:g>"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nízká"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Střední"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Vysoká"</string>
+    <string name="high_importance" msgid="730741630855788381">"Naléhavá"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez zvukového a vizuálního vyrušení"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Zobrazovat tiše"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Vydat zvukový signál"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Vydat zvukový signál a vyskočit na obrazovku"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Další nastavení"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Nastavení oznámení aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 76841dd..675029d 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Låseskærm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Indstillinger"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Oversigt."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Låseskærm til arbejde"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Luk"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi er slået fra."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Udvid"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skjul"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skærmen er fastgjort"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage og Overblik, og hold fingeren nede for at frigøre skærmen."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Dette fastholder skærmen i visningen, indtil du frigør den. Tryk på Tilbage, og hold fingeren nede for at frigøre skærmen."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK, det er forstået"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tak"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Til"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Fra"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Med kontrolelementer til underretninger om strøm kan du konfigurere et vigtighedsniveau fra 0 til 5 for en apps underretninger. \n\n"<b>"Niveau 5"</b>\n"- Vis øverst på listen over underretninger \n- Tillad afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 4"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se altid smugkig \n\n"<b>"Niveau 3"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n\n"<b>"Niveau 2"</b>\n"- Ingen afbrydelse af fuld skærm \n Se aldrig smugkig \n- Ingen lyd og vibration \n\n"<b>"Niveau 1"</b>\n"- Ingen afbrydelse af fuld skærm \n- Se aldrig smugkig \n- Ingen lyd eller vibration \n- Skjul fra låseskærm og statusbjælke \n- Vis nederst på listen over underretninger \n\n"<b>"Niveau 0"</b>\n"- Bloker alle underretninger fra appen."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Underretninger"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Du modtager ikke længere disse underretninger."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-underretninger til"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Lav"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Middel"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Høj"</string>
+    <string name="high_importance" msgid="730741630855788381">"Haster"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ingen lyd eller pop op-visning"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Vis lydløst"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Med lyd"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Med lyd og pop op-visning"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
     <string name="notification_done" msgid="5279426047273930175">"Udfør"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolelementer til underretninger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 23f0bd0..fb580cd 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Sperrbildschirm"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Einstellungen"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Übersicht"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Sperrbildschirm für Arbeitsprofil"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Schließen"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WLAN ist deaktiviert."</string>
@@ -331,7 +330,7 @@
     <string name="recents_search_bar_label" msgid="8074997400187836677">"Suche"</string>
     <string name="recents_launch_error_message" msgid="2969287838120550506">"<xliff:g id="APP">%s</xliff:g> konnte nicht gestartet werden."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ist im abgesicherten Modus deaktiviert."</string>
-    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Alle löschen"</string>
+    <string name="recents_stack_action_button_label" msgid="6593727103310426253">"Alle schließen"</string>
     <string name="recents_incompatible_app_message" msgid="5075812958564082451">"Das Teilen des Bildschirms wird in dieser App nicht unterstützt"</string>
     <string name="recents_drag_hint_message" msgid="2649739267073203985">"Hierher ziehen, um den Bildschirm zu teilen"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Geteilte Schaltfläche – horizontal"</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Maximieren"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Minimieren"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Bildschirm ist fixiert"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Der Bildschirm bleibt so lange eingeblendet, bis du die Fixierung aufhebst. Berühre und halte dazu \"Zurück\" und \"Übersicht\"."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Der Bildschirm bleibt so lange eingeblendet, bis du die Fixierung aufhebst. Berühre und halte dazu \"Übersicht\"."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nein danke"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ausblenden?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"An"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Aus"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Mit den erweiterten Benachrichtigungseinstellungen kannst du für App-Benachrichtigungen eine Wichtigkeitsstufe von 0 bis 5 festlegen. \n\n"<b>"Stufe 5"</b>" \n- Auf der Benachrichtigungsleiste ganz oben anzeigen \n- Vollbildunterbrechung zulassen \n- Immer kurz einblenden \n\n"<b>"Stufe 4"</b>" \n- Keine Vollbildunterbrechung \n- Immer kurz einblenden \n\n"<b>"Stufe 3"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n\n"<b>"Stufe 2"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n- Weder Ton noch Vibration \n\n"<b>"Stufe 1"</b>" \n- Keine Vollbildunterbrechung \n- Nie kurz einblenden \n- Weder Ton noch Vibration \n- Auf Sperrbildschirm und Statusleiste verbergen \n- Auf der Benachrichtigungsleiste ganz unten anzeigen \n\n"<b>"Stufe 0"</b>" \n- Alle Benachrichtigungen der App sperren"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Benachrichtigungen"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Du erhältst diese Benachrichtigungen nicht mehr."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-Benachrichtigungen für"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Niedrig"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Mittel"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Hoch"</string>
+    <string name="high_importance" msgid="730741630855788381">"Dringend"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Kein akustisches Signal und keine visuelle Unterbrechung"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Ohne Ton anzeigen"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Akustisches Signal"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Akustisches Signal und Bildschirmbenachrichtigung"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-Benachrichtigungseinstellungen"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index a11ee0d..6190f07 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Κλείδωμα οθόνης."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ρυθμίσεις"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Επισκόπηση."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Οθόνη κλειδωμένης εργασίας"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Κλείσιμο"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Το Wi-fi απενεργοποιήθηκε."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ανάπτυξη"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Σύμπτυξη"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Η οθόνη καρφιτσώθηκε"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Με αυτόν τον τρόπο παραμένει σε προβολή μέχρι να το ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα τα στοιχεία \"Επιστροφή\" και \"Επισκόπηση\" για ξεκαρφίτσωμα."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Με αυτόν τον τρόπο παραμένει σε προβολή μέχρι να το ξεκαρφιτσώσετε. Αγγίξτε παρατεταμένα την \"Επισκόπηση\" για ξεκαρφίτσωμα."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Το κατάλαβα"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Όχι"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Απόκρυψη <xliff:g id="TILE_LABEL">%1$s</xliff:g>;"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Ενεργή"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Ανενεργή"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Με τα στοιχεία ελέγχου ειδοποίησης ισχύος, μπορείτε να ορίσετε ένα επίπεδο βαρύτητας από 0 έως 5 για τις ειδοποιήσεις μιας εφαρμογής. \n\n"<b>"Επίπεδο 5"</b>" \n- Εμφάνιση στην κορυφή της λίστας ειδοποιήσεων \n- Να επιτρέπεται η διακοπή πλήρους οθόνης \n- Να γίνεται πάντα σύντομη προβολή \n\n"<b>"Επίπεδο 4"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να γίνεται πάντα σύντομη προβολή \n\n"<b>"Επίπεδο 3"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n\n"<b>"Επίπεδο 2"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n- Να μην χρησιμοποιείται ποτέ ήχος και δόνηση \n\n"<b>"Επίπεδο 1"</b>" \n- Αποτροπή διακοπής πλήρους οθόνης \n- Να μην γίνεται ποτέ σύντομη προβολή \n- Να μην χρησιμοποιείται ποτέ ήχος και δόνηση \n- Απόκρυψη από την οθόνη κλειδώματος και τη γραμμή κατάστασης \n- Εμφάνιση στο κάτω μέρος της λίστας ειδοποιήσεων \n\n"<b>"Επίπεδο 0"</b>" \n- Αποκλεισμός όλων των ειδοποιήσεων από την εφαρμογή"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Ειδοποιήσεις"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Δεν θα λαμβάνεται πλέον αυτές τις ειδοποιήσεις."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Ειδοποιήσεις <xliff:g id="APP">%s</xliff:g> για"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Χαμηλή"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Μεσαία"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Υψηλή"</string>
+    <string name="high_importance" msgid="730741630855788381">"Επείγον"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Χωρίς ηχητική ή οπτική διακοπή"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Εμφάνιση χωρίς ειδοποίηση"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Αναπαραγωγή ήχου"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Αναπαραγωγή ήχου και εμφάνιση στην οθόνη"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
     <string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Στοιχεία ελέγχου κοινοποίησης <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 883c812..9d74a2f 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lock screen."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Settings"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Overview."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Work lock screen"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Close"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi turned off."</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 883c812..9d74a2f 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lock screen."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Settings"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Overview."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Work lock screen"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Close"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi turned off."</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 883c812..9d74a2f 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lock screen."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Settings"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Overview."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Work lock screen"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Close"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi turned off."</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index e20b1cae..24a82ab 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Pantalla bloqueada"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Configuración"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Recientes"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Pantalla bloqueada del perfil de trabajo"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Cerrar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi desactivado"</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Contraer"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Pantalla fija"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Esta función mantiene la pantalla visible hasta que dejes de fijarla. Para ello, mantén presionados los botones Atrás y Recientes."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Esta función mantiene la pantalla visible hasta que dejes de fijarla. Para ello, mantén presionado el botón Recientes."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendido"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gracias"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Activado"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivado"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Con los controles de activación de notificaciones, puedes establecer un nivel de importancia para las notificaciones de una app. \n\n"<b>"Nivel 5"</b>" \n- Mostrar en la parte superior de la lista de notificaciones. \n- Permitir interrupción en la pantalla completa. \n- Mostrar siempre. \n\n"<b>"Nivel 4"</b>" \n- No permitir interrupción en la pantalla completa. \n- Mostrar siempre. \n\n"<b>"Nivel 3"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n\n"<b>"Nivel 2"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n- No sonar ni vibrar. \n\n"<b>"Nivel 1"</b>" \n- No permitir interrupción en la pantalla completa. \n- No mostrar. \n- No sonar ni vibrar. \n- Ocultar de la pantalla bloqueada y la barra de estado. \n- Mostrar al final de la lista de notificaciones. \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas las notificaciones de la app."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificaciones"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ya no recibirás estas notificaciones."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificaciones de <xliff:g id="APP">%s</xliff:g> para"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baja"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Media"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"No emitir sonido ni mostrar"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar sin emitir sonido"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir sonido"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir sonido y mostrar en pantalla"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
     <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index a2bf7a3..76ea158 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Pantalla de bloqueo."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ajustes"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Aplicaciones recientes."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Pantalla de bloqueo para el perfil de trabajo"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Cerrar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi desactivado."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Mostrar"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ocultar"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Pantalla fijada"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsados los botones Atrás y Aplicaciones recientes."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"La pantalla se mantiene visible hasta que dejas de fijarla. Para ello, mantén pulsado el botón Aplicaciones recientes."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendido"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, gracias"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"¿Ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Sí"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"No"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Los controles de energía de las notificaciones permiten establecer un nivel de importancia de 0 a 5 para las notificaciones de las aplicaciones. \n\n"<b>"Nivel 5"</b>" \n- Mostrar en la parte superior de la lista de notificaciones \n- Permitir interrumpir en el modo de pantalla completa \n- Mostrar siempre \n\n"<b>"Nivel 4"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- Mostrar siempre \n\n"<b>"Nivel 3"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- No mostrar nunca \n\n"<b>"Nivel 2"</b>" \n- Evitar interrumpir en el modo de pantalla completa\n- No mostrar nunca \n- No emitir sonido ni vibrar nunca \n\n"<b>"Nivel 1"</b>" \n- Evitar interrumpir en el modo de pantalla completa \n- No mostrar nunca \n- No emitir sonido ni vibrar nunca \n- Ocultar de la pantalla de bloqueo y de la barra de estado \n- Mostrar en la parte inferior de la lista de notificaciones \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas las notificaciones de la aplicación"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificaciones"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ya no recibirás estas notificaciones."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificaciones de <xliff:g id="APP">%s</xliff:g>:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baja"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Media"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Sin sonido ni interrupción visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir sonido"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir sonido y mostrar en pantalla"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Más ajustes"</string>
     <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index ed6e7f4..696585b 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Kuva lukustamine."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Seaded"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Ülevaade."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Töö lukustuskuva"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Sulgemine"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WiFi on välja lülitatud."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Laiendamine"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Ahendamine"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekraan on kinnitatud"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppe Tagasi ja Ülevaade."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"See hoitakse kuval, kuni selle vabastate. Vabastamiseks puudutage pikalt nuppu Ülevaade."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Selge"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Tänan, ei"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Kas peita <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Sees"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Väljas"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Toite märguannete juhtnuppudega saate määrata rakenduse märguannete tähtsuse taseme vahemikus 0–5. \n\n"<b>"5. tase"</b>" \n- Kuva märguannete loendi ülaosas\n- Luba täisekraanil häirimine \n- Kuva alati ekraani servas \n\n"<b>"4. tase"</b>" \n- Keela täisekraanil häirimine \n- Kuva alati ekraani servas \n\n"<b>"3. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n\n"<b>"2. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n- Ära kunagi helise ega vibreeri \n\n"<b>"1. tase"</b>" \n- Keela täisekraanil häirimine \n- Ära kunagi kuva ekraani servas \n- Ära kunagi helise ega vibreeri \n- Peida lukustuskuval ja olekuribal \n- Kuva märguannete loendi allosas \n\n"<b>"Tase 0"</b>" \n- Blokeeri kõik rakenduse märguanded"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Märguanded"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Te ei saa enam neid märguandeid."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Rakenduse <xliff:g id="APP">%s</xliff:g> märguanded:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Väike"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Keskmine"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Suur"</string>
+    <string name="high_importance" msgid="730741630855788381">"Kiireloomuline"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Heli ja visuaalne katkestus puudub"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Kuva vaikselt"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Esita heli"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Esita heli ja tõsta märguanne esile"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Rohkem seadeid"</string>
     <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguannete juhtnupud"</string>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index c8e9ade..72cd63d 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Pantaila blokeatzeko aukera."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ezarpenak"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Ikuspegi orokorra."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Laneko pantaila blokeatua"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Itxi"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi konexioa desaktibatu egin da."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Zabaldu"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Tolestu"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Pantaila ainguratuta dago"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Atzera\" eta \"Ikuspegi orokorra\" botoiak."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Horrela, ikusgai egongo da aingura kendu arte. Aingura kentzeko, eduki sakatuta \"Ikuspegi orokorra\" botoia."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ados"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ez, eskerrik asko"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ezkutatu nahi duzu?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Aktibatuta"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desaktibatuta"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Bateria-mailaren arabera jakinarazpenak kontrolatzeko aukerekin, 0 eta 5 bitarteko garrantzi-mailetan sailka ditzakezu aplikazioen jakinarazpenak. \n\n"<b>"5. maila"</b>" \n- Erakutsi jakinarazpenen zerrendaren goialdean. \n- Baimendu etetea pantaila osoko moduan zaudenean. \n- Agerrarazi beti jakinarazpenak. \n\n"<b>"4. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Agerrarazi beti jakinarazpenak. \n\n"<b>"3. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n\n"<b>"2. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n- Ez egin soinurik edo dardararik inoiz. \n\n"<b>"1. maila"</b>" \n- Galarazi etetea pantaila osoko moduan zaudenean. \n- Ez agerrarazi jakinarazpenik inoiz. \n- Ez egin soinurik edo dardararik inoiz. \n- Ezkutatu pantaila blokeatutik eta egoera-barratik. \n- Erakutsi jakinarazpenen zerrendaren behealdean. \n\n"<b>"0. maila"</b>" \n- Blokeatu aplikazioaren jakinarazpen guztiak."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Jakinarazpenak"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Aurrerantzean ez duzu jasoko horrelako jakinarazpenik."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> aplikazioaren jakinarazpenak"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Txikia"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Ertaina"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Handia"</string>
+    <string name="high_importance" msgid="730741630855788381">"Premiazkoa"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ez egin soinurik eta ez erakutsi"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Erakutsi soinurik egin gabe"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Egin soinua"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Egin soinua eta erakutsi pantailan"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
     <string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpenak kontrolatzeko aukerak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 1992dd6..7c63beb 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"قفل صفحه."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"تنظیمات"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"نمای کلی."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"صفحه حالت قفل نمایه کاری"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"بستن"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"‏Wi-Fi خاموش شد."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"بزرگ کردن"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"کوچک کردن"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"صفحه نمایش پین شد"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"تا زمانی که پین را بردارید، در نما نگه‌داشته می‌شود. برای برداشتن پین، «برگشت» و «نمای کلی» را لمس کنید و نگه‌دارید."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"تا زمانی که پین را بردارید، در نما نگه‌داشته می‌شود. برای برداشتن پین، «نمای کلی» را لمس کنید و نگه‌دارید."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"متوجه شدم"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"نه متشکرم"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> مخفی شود؟"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"روشن"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"خاموش"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"با کنترل‌های قدرتمند اعلان می‌توانید سطح اهمیت اعلان‌های هر برنامه را از ۰ تا ۵ تعیین کنید. \n\n"<b>"سطح ۵"</b>" \n- در صدر فهرست اعلان‌ها نشان داده می‌شود \n- وقفه برای نمایش تمام‌صفحه مجاز است \n- همیشه اجمالی نشان داده می‌شود \n\n"<b>"سطح ۴"</b>" \n- وقفه برای نمایش تمام‌صفحه مجاز نیست \n- همیشه اجمالی نشان داده می‌شود \n\n"<b>"سطح ۳"</b>" \n- وقفه برای نمایش تمام‌صفحه مجاز نیست \n- هیچ‌وقت اجمالی نشان داده نمی‌شود \n\n"<b>"سطح ۲"</b>" \n- وقفه برای نمایش تمام‌صفحه مجاز نیست \n- هیچ‌وقت اجمالی نشان داده نمی‌شود \n- هیچ‌وقت صدا و لرزش ایجاد نمی‌کند \n\n"<b>"سطح ۱"</b>" \n- نمایش تمام صفحه مجاز نیست \n- هیچ‌وقت اجمالی نشان داده نمی‌شود \n- هیچ‌وقت صدا یا لرزش ایجاد نمی‌کند \n- در قفل صفحه و نوار وضعیت پنهان است \n- در پایین فهرست اعلان‌ها نشان داده می‌شود \n\n"<b>"سطح ۰"</b>" \n- همه اعلان‌های این برنامه مسدود است"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"اعلان‌ها"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"دیگر این اعلان‌ها را دریافت نخواهید کرد."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"اعلان‌های <xliff:g id="APP">%s</xliff:g> برای"</string>
+    <string name="min_importance" msgid="7559703098688382595">"کم"</string>
+    <string name="low_importance" msgid="6891335321576225228">"متوسط"</string>
+    <string name="default_importance" msgid="6400766013567512061">"زیاد"</string>
+    <string name="high_importance" msgid="730741630855788381">"فوری"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"بدون وقفه صوتی و تصویری"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"نمایش به‌صورت بی‌صدا"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"پخش صدا"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"پخش صدا و صفحه بازشو"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"تنظیمات بیشتر"</string>
     <string name="notification_done" msgid="5279426047273930175">"تمام"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"کنترل‌های اعلان <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 7176df4..d6ce213 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lukitse näyttö."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Asetukset"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Viimeisimmät."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Työlukitusnäyttö"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Sulje"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi poistettiin käytöstä."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Laajenna."</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Tiivistä."</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Näyttö on kiinnitetty"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Edellinen ja Viimeisimmät."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Pysyy näkyvissä, kunnes irrotat sen. Irrota painamalla pitkään Viimeisimmät."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Selvä"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ei kiitos"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Piilotetaanko <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Käytössä"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Pois käytöstä"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ilmoitusten tehohallinnan avulla voit määrittää sovelluksen ilmoituksille tärkeystason väliltä 0–5. \n\n"<b>"Taso 5"</b>" \n– Ilmoitukset näytetään ilmoitusluettelon yläosassa \n– Näkyminen koko näytön tilassa sallitaan \n– Ilmoitukset kurkistavat aina näytölle\n\n"<b>"Taso 4"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ilmoitukset kurkistavat aina näytölle \n\n"<b>"Taso 3"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n\n"<b>"Taso 2"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n– Ei ääniä eikä värinää \n\n"<b>"Taso 1"</b>" \n– Näkyminen koko näytön tilassa estetään \n– Ei kurkistamista \n– Ei ääniä eikä värinää \n– Ilmoitukset piilotetaan lukitusnäytöltä ja tilapalkista \n– Ilmoitukset näytetään ilmoitusluettelon alaosassa \n\n"<b>"Taso 0"</b>" \n– Kaikki sovelluksen ilmoitukset estetään"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Ilmoitukset"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Et saa näitä ilmoituksia enää."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Sovelluksen <xliff:g id="APP">%s</xliff:g> ilmoitukset:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Matala"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Keskitaso"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Korkea"</string>
+    <string name="high_importance" msgid="730741630855788381">"Kiireellinen"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ei ääntä tai näkyvää ilmoitusta"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Näkyy ilman ääntä"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Ääni"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Ääni, ilmoitus näkyy näytöllä"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
     <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ilmoitusten hallinta"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 3ec4ecc..897890a 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Écran de verrouillage"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Paramètres"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Aperçu"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Verrouillage de l\'écran du profil professionnel"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Fermer"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi désactivé"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 36db7dd..90bec35 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Écran de verrouillage"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Paramètres"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Aperçu"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Écran de verrouillage du profil professionnel"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Fermer"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi désactivé."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Développer"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Réduire"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Écran épinglé"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Cet écran est épinglé jusqu\'à l\'annulation de l\'opération. Pour annuler l\'épinglage, appuyez de manière prolongée sur les boutons Retour et Aperçu."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Cet écran est épinglé jusqu\'à l\'annulation de l\'opération. Pour annuler l\'épinglage, appuyez de manière prolongée sur le bouton Aperçu."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, merci"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Masquer <xliff:g id="TILE_LABEL">%1$s</xliff:g> ?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Activé"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Désactivé"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Grâce aux commandes de gestion des notifications, vous pouvez définir le niveau d\'importance (compris entre 0 et 5) des notifications d\'une application. \n\n"<b>"Niveau 5"</b>" \n- Afficher en haut de la liste des notifications \n- Autoriser l\'interruption en plein écran \n- Toujours en aperçu \n\n"<b>"Niveau 4"</b>" \n- Empêcher l\'interruption en plein écran \n- Toujours en aperçu \n\n"<b>"Niveau 3"</b>" \n- Empêcher l\'interruption en plein écran \n- Jamais en aperçu \n\n"<b>"Niveau 2"</b>" \n- Empêcher l\'interruption en plein écran \n- Jamais en aperçu \n- Ne jamais émettre de signal sonore ni déclencher le vibreur \n\n"<b>"Niveau 1"</b>" \n- Empêcher l\'interruption en plein écran \n- Jamais en aperçu \n- Ne jamais émettre de signal sonore ni déclencher le vibreur \n- Masquer les notifications dans l\'écran de verrouillage et la barre d\'état \n- Afficher au bas de la liste des notifications \n\n"<b>"Niveau 0"</b>" \n- Bloquer toutes les notifications de l\'application"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifications"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Vous ne recevrez plus ces notifications."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notifications de l\'application <xliff:g id="APP">%s</xliff:g> pour"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Faible"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Moyenne"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Élevée"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Aucune interruption sonore ni visuelle"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Affichage silencieux"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Alerte sonore"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Alerte sonore et affichage à l\'écran"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
     <string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Commandes de notification de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index d7824e4..7d9b137 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Pantalla de bloqueo."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Configuración"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Visión xeral."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Pantalla de bloqueo do perfil de traballo"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Pechar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi desactivada."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ampliar"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Contraer"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A pantalla está fixada"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"A pantalla manterase visible ata que a soltes. Para facelo, mantén premido Atrás e Visión xeral."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"A pantalla manterase visible ata que a soltes. Para facelo, mantén premido Visión xeral."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"De acordo"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Non, grazas"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Queres ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Activar"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desactivar"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Cos controis de notificacións mellorados, podes asignarlles un nivel de importancia comprendido entre 0 e 5 ás notificacións dunha aplicación determinada. \n\n"<b>"Nivel 5"</b>" \n- Mostrar na parte superior da lista de notificacións. \n- Permitir interrupcións no modo de pantalla completa. \n- Mostrar sempre. \n\n"<b>"Nivel 4"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Mostrar sempre. \n\n"<b>"Nivel 3"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n\n"<b>"Nivel 2"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n- Non soar nin vibrar nunca. \n\n"<b>"Nivel 1"</b>" \n- Impedir interrupcións no modo de pantalla completa. \n- Non mostrar nunca. \n- Non soar nin vibrar nunca. \n- Ocultar na pantalla de bloqueo e na barra de estado. \n- Mostrar na parte inferior da lista de notificacións. \n\n"<b>"Nivel 0"</b>" \n- Bloquear todas as notificacións da aplicación."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificacións"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Deixarás de recibir estas notificacións."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificacións da aplicación <xliff:g id="APP">%s</xliff:g> para"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baixa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Media"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urxente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Nin son nin interrupción visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar en silencio"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir son"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir son e aparecer na pantalla"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
     <string name="notification_done" msgid="5279426047273930175">"Feito"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controis de notificacións de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index e86f759..3bc21e1 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"લૉક સ્ક્રીન."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"સેટિંગ્સ"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"વિહંગાવલોકન."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"કાર્ય લૉક સ્ક્રીન"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"બંધ કરો"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi બંધ કર્યું."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"વિસ્તૃત કરો"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"સંકુચિત કરો"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"સ્ક્રીન પિન કરેલ છે"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે પાછળ અને વિહંગાવલોકન ટચ કરો અને પકડી રાખો."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"તમે જ્યાં સુધી અનપિન કરશો નહીં ત્યાં સુધી આ તેને દૃશ્યક્ષમ રાખે છે. અનપિન કરવા માટે વિહંગાવલોકન ટચ કરો અને પકડી રાખો."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"સમજાઈ ગયું"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"નહીં આભાર"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ને છુપાવીએ?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ચાલુ"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"બંધ"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"પાવર સૂચના નિયંત્રણો સાથે, તમે ઍપ્લિકેશનની સૂચનાઓ માટે 0 થી 5 સુધીના મહત્વના સ્તરને સેટ કરી શકો છો. \n\n"<b>"સ્તર 5"</b>" \n- સૂચના સૂચિની ટોચ પર બતાવો \n- પૂર્ણ સ્ક્રીન અવરોધની મંજૂરી આપો \n- હંમેશાં ત્વરિત દૃષ્ટિ કરો \n\n"<b>"સ્તર 4"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- હંમેશાં ત્વરિત દૃષ્ટિ કરો \n\n"<b>"સ્તર 3"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n\n"<b>"સ્તર 2"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n- ક્યારેય અવાજ અને વાઇબ્રેશન કરશો નહીં \n\n"<b>"સ્તર 1"</b>" \n- પૂર્ણ સ્ક્રીન અવરોધ અટકાવો \n- ક્યારેય ત્વરિત દૃષ્ટિ કરશો નહીં \n- ક્યારેય અવાજ અથવા વાઇબ્રેટ કરશો નહીં \n- લૉક સ્ક્રીન અને સ્થિતિ બારથી છુપાવો \n- સૂચના સૂચિના તળિયા પર બતાવો \n\n"<b>"સ્તર 0"</b>" \n- ઍપ્લિકેશનની તમામ સૂચનાઓને અવરોધિત કરો"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"સૂચનાઓ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"તમને હવે આ સૂચનાઓ મળશે નહીં."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"આ માટે <xliff:g id="APP">%s</xliff:g> સૂચનાઓ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"નિમ્ન"</string>
+    <string name="low_importance" msgid="6891335321576225228">"મધ્યમ"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ઉચ્ચ"</string>
+    <string name="high_importance" msgid="730741630855788381">"તાત્કાલિક"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"કોઈ અવાજ અથવા વિઝ્યુઅલ અવરોધ નહીં"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"ચુપચાપ બતાવો"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"અવાજ કરો"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"અવાજ કરો અને સ્ક્રીન પર બતાવો"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"વધુ સેટિંગ્સ"</string>
     <string name="notification_done" msgid="5279426047273930175">"થઈ ગયું"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> સૂચના નિયંત્રણો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 13dac84..e019e09 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"लॉक स्क्रीन."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"सेटिंग"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"अवलोकन."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"कार्य लॉक स्‍क्रीन"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"बंद करें"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"वाई-फ़ाई को बंद किया गया."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index f160f2df..6414afc 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -186,8 +186,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Zaključavanje zaslona."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Postavke"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pregled."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Zaključan zaslon radnog profila"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zatvaranje"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi isključen."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Proširivanje"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sažimanje"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Zaslon je prikvačen"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite i zadržite Natrag i Pregled da biste ga otkvačili."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Zaslon će tako ostati u prvom planu dok ga ne otkvačite. Dodirnite i zadržite Pregled da biste ga otkvačili."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Shvaćam"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite li sakriti pločicu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Uključeno"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Isključeno"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Napredne kontrole obavijesti omogućuju vam da postavite razinu važnosti za obavijesti aplikacije od 0 do 5. \n\n"<b>"Razina 5"</b>" \n– prikaži na vrhu popisa obavijesti \n– dopusti prekide prikaza na cijelom zaslonu \n– uvijek dopusti brzi pregled \n\n"<b>"Razina 4"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– uvijek dopusti brzi pregled \n\n"<b>"Razina 3"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled\n\n"<b>"Razina 2"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled \n– nikad ne emitiraj zvuk ni vibraciju \n\n"<b>"Razina 1"</b>" \n– onemogući prekid prikaza na cijelom zaslonu \n– nikad ne dopusti brzi pregled \n– nikad ne emitiraj zvuk ni vibraciju \n– ne prikazuj na zaključanom zaslonu i traci statusa \n– prikaži na dnu popisa obavijesti \n\n"<b>"Razina 0"</b>" \n– blokiraj sve obavijesti aplikacije"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Obavijesti"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Više nećete primati te obavijesti."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Obavijesti aplikacije <xliff:g id="APP">%s</xliff:g> za"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Niski"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Srednji"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Visoki"</string>
+    <string name="high_importance" msgid="730741630855788381">"Hitni"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez zvučnog ili vizualnog ometanja"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Prikaži tiho"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Reproduciraj zvuk"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Reproduciraj zvuk i prikaži na zaslonu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrole obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 94b0f0e..2a891b7 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lezárási képernyő."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Beállítások"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Áttekintés."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Munka lezárási képernyővel"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Bezárás"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi kikapcsolva."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Kibontás"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Összecsukás"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A képernyő rögzítve van"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva a Vissza és az Áttekintés lehetőséget."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Megjelenítve tartja addig, amíg Ön fel nem oldja a rögzítést. A feloldáshoz tartsa lenyomva az Áttekintés lehetőséget."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Értem"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nem, köszönöm"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Elrejti ezt: <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Bekapcsolva"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Kikapcsolva"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Az értesítési beállítások révén 0-tól 5-ig állíthatja be a fontossági szintet az alkalmazás értesítéseinél. \n\n"<b>"5. szint"</b>" \n– Megjelenítés az értesítési lista tetején \n– Teljes képernyő megszakításának engedélyezése \n– Mindig felugrik \n\n"<b>"4. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Mindig felugrik \n\n"<b>"3. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n\n"<b>"2. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n– Soha nincs hangjelzés és rezgés \n\n"<b>"1. szint"</b>" \n– Teljes képernyő megszakításának megakadályozása \n– Soha nem ugrik fel \n– Soha nincs hangjelzés vagy rezgés \n– Elrejtés a lezárási képernyőről és az állapotsávról \n– Megjelenítés az értesítési lista alján \n\n"<b>"0. szint"</b>" \n– Az alkalmazás összes értesítésének letiltása"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Értesítések"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Többé nem jelennek meg ezek az értesítések."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-értesítések"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nem fontos"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Közepesen fontos"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Fontos"</string>
+    <string name="high_importance" msgid="730741630855788381">"Sürgős"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Hangjelzés és vizuális megszakítás nélkül"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Megjelenítés hangjelzés nélkül"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Hangjelzés"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Hangjelzés és felugró értesítés a képernyőn"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"További beállítások"</string>
     <string name="notification_done" msgid="5279426047273930175">"Kész"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g>-értesítések vezérlői"</string>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 8889a96..c17c522 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Էկրանի կողպում:"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Կարգավորումներ"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Համատեսք"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Աշխատանքային պրոֆիլի կողպէկրան"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Փակել"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>:"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi-ն անջատվեց:"</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Ընդարձակել"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Կոծկել"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Էկրանն ամրացված է"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Հետ և Համատեսք կոճակները:"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Էկրանը կմնա տեսադաշտում, մինչև այն ապամրացնեք: Ապամրացնելու համար հպեք և պահեք Համատեսք կոճակը:"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Եղավ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ոչ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Թաքցնե՞լ <xliff:g id="TILE_LABEL">%1$s</xliff:g>-ը:"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Միացնել"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Անջատել"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ծանուցումների ընդլայնված կառավարման օգնությամբ կարող եք յուրաքանչյուր հավելվածի ծանուցումների համար նշանակել կարևորության աստիճան՝ 0-5 սահմաններում: \n\n"<b>"5-րդ աստիճան"</b>" \n- Ցուցադրել ծանուցումների ցանկի վերևում \n- Թույլատրել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n"<b>"4-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Միշտ ցուցադրել կարճ ծանուցումները \n\n"<b>"3-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n\n"<b>"2-րդ աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n\n"<b>"1-ին աստիճան"</b>" \n- Արգելել լիաէկրան ընդհատումները \n- Արգելել կարճ ծանուցումների ցուցադրումը \n- Անջատել ձայնը և թրթռումը \n- Չցուցադրել կողպէկրանում և կարգավիճակի գոտում \n- Ցուցադրել ծանուցումների ցանկի ներքևում \n\n"<b>"0-րդ աստիճան"</b>\n"- Արգելափակել հավելվածի բոլոր ծանուցումները"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Ծանուցումներ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Այս ծանուցումներն այլևս չեք ստանա։"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> ծանուցումներ հետևյալ ալիքի համար"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Ցածր"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Միջին"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Բարձր"</string>
+    <string name="high_importance" msgid="730741630855788381">"Շտապ"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Առանց ձայնի և տեսողական ընդհատումների"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Ցույց տալ անձայն"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Ձայն հանել"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Ձայն հանել և ցուցադրել էկրանին"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
     <string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ծանուցումների կառավարներ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 2ccbda4..e7d7c5d 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Layar kunci."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Setelan"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Ringkasan."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Layar kunci kantor"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Tutup"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi dinonaktifkan."</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 9d2d43f..3807554 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lásskjár."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Stillingar"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Yfirlit."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Vinnulásskjár"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Loka"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Slökkt á Wi-Fi."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Stækka"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Minnka"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skjárinn er festur"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Þetta heldur þessu opnu þangað til þú losar það. Haltu fingri á „Til baka“ og „Yfirlit“ til að losa."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Þetta heldur þessu opnu þangað til þú losar það. Haltu fingri á „Yfirlit“ til að losa."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ég skil"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei, takk"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fela <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Kveikt"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Slökkt"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Með orkutilkynningastýringum geturðu stillt mikilvægi frá 0 upp í 5 fyrir tilkynningar forrita. \n\n"<b>"Stig 5"</b>" \n- Sýna efst á tilkynningalista \n- Leyfa truflun þegar birt er á öllum skjánum \n- Kíkja alltaf \n\n"<b>"Stig 4"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja alltaf \n\n"<b>"Stig 3"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n\n"<b>"Stig 2"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n- Slökkva á hljóði og titringi \n\n"<b>"Stig 1"</b>" \n- Hindra truflun við birtingu á öllum skjánum \n- Kíkja aldrei \n- Slökkva á hljóði og titringi \n- Fela á lásskjá og stöðustiku \n- Sýna neðst á tilkynningalista \n\n"<b>"Stig 0"</b>" \n- Setja allar tilkynningar frá forriti á bannlista"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Tilkynningar"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Þú færð þessar tilkynningar ekki framar."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Tilkynningar frá <xliff:g id="APP">%s</xliff:g> fyrir"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Ekki mikilvægt"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Í meðallagi"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Mikilvægt"</string>
+    <string name="high_importance" msgid="730741630855788381">"Áríðandi"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ekkert hljóð eða sjónræn truflun"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Sýna án hljóðs"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Spila hljóð"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Spila hljóð og birta sprettitilkynningu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Tilkynningastýringar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 93bbd43..967f353 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Schermata di blocco."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Impostazioni"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Panoramica."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Schermata di blocco del profilo di lavoro"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Chiudi"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi disattivato."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Espandi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Comprimi"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"La schermata è bloccata"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tieni premuto Indietro e Panoramica."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"La schermata rimane visibile finché non viene disattivato il blocco su schermo. Per disattivarlo, tieni premuto Panoramica."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"No, grazie"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Nascondere <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"On"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Off"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"I controlli di gestione delle notifiche ti consentono di impostare un livello di importanza compreso tra 0 e 5 per le notifiche di un\'app. \n\n"<b>"Livello 5"</b>" \n- Mostra in cima all\'elenco di notifiche \n- Consenti l\'interruzione a schermo intero \n- Visualizza sempre \n\n"<b>"Livello 4"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Visualizza sempre \n\n"<b>"Livello 3"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n\n"<b>"Livello 2"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n- Non emettere mai suoni e vibrazioni \n\n"<b>"Livello 1"</b>" \n- Impedisci l\'interruzione a schermo intero \n- Non visualizzare mai \n- Non emettere mai suoni e vibrazioni \n- Nascondi da schermata di blocco e barra di stato \n- Mostra in fondo all\'elenco di notifiche \n\n"<b>"Livello 0"</b>" \n- Blocca tutte le notifiche dell\'app"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notifiche"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Non riceverai più queste notifiche."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notifiche di <xliff:g id="APP">%s</xliff:g> per"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Bassa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Media"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Senza suoneria o interruzione visiva"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostra silenziosamente"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Con suoneria"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Con suoneria e visualizzazione sullo schermo"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Altre impostazioni"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fine"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controlli di notifica per <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 6b5b115..7dac321 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"מסך נעילה."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"הגדרות"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"סקירה."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"מסך נעילה בעבודה"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"סגור"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"‏Wifi כבוי."</string>
@@ -444,10 +443,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"הרחב"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"כווץ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"המסך מוצמד"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"נשאר בתצוגה עד לביטול ההצמדה. גע בלחצנים \'הקודם\' ו\'סקירה\' והחזק כדי לבטל את ההצמדה."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"נשאר בתצוגה עד לביטול ההצמדה. גע בלחצן \'סקירה\' והחזק כדי לבטל את ההצמדה."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"הבנתי"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"לא, תודה"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"להסתיר<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -514,28 +511,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"פועל"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"כבוי"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"בעזרת פקדים של הודעות הפעלה, תוכל להגדיר רמת חשיבות מ-0 עד 5 להודעות אפליקציה. \n\n"<b>"רמה 5"</b>" \n- הצג בראש רשימת ההודעות \n- אפשר הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 4"</b>" \n- מנע הפרעה במסך מלא \n- תמיד אפשר הצצה \n\n"<b>"רמה 3"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n\n"<b>"רמה 2"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n\n"<b>"רמה 1"</b>" \n- מנע הפרעה במסך מלא \n- אף פעם אל תאפשר הצצה \n- אף פעם אל תאפשר קול ורטט \n- הסתר ממסך הנעילה ומשורת הסטטוס \n- הצג בתחתית רשימת ההודעות \n\n"<b>"רמה 0"</b>" \n- חסום את כל ההודעות מהאפליקציה"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"הודעות"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"לא תקבל את ההודעות האלה יותר."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"הודעות <xliff:g id="APP">%s</xliff:g> עבור"</string>
+    <string name="min_importance" msgid="7559703098688382595">"נמוכה"</string>
+    <string name="low_importance" msgid="6891335321576225228">"בינונית"</string>
+    <string name="default_importance" msgid="6400766013567512061">"גבוהה"</string>
+    <string name="high_importance" msgid="730741630855788381">"דחופה"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ללא צליל וללא הפרעה ויזואלית"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"הצג ללא צליל"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"השמע צליל"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"השמע צליל והצג במסך"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
     <string name="notification_done" msgid="5279426047273930175">"סיום"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> פקדי הודעות"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index aa52801..f01b82d 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ロック画面"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"設定"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"最近"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"仕事用プロファイルのロック画面"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"閉じる"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-FiをOFFにしました。"</string>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index bb73c4b..ca8978d 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ეკრანის დაბლოკვა."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"პარამეტრები"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"მიმოხილვა"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"სამსახურის ჩაკეტილი ეკრანი"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"დახურვა"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi გამორთულია."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"გავრცობა"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ჩაკეცვა"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ეკრანი ჩამაგრებულია"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „უკან და მიმოხილვა“-ს."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ამით ის დარჩება ხედში ჩამაგრების მოხსნამდე. ჩამაგრების მოსახსნელად, ხანგრძლივად შეეხეთ „მიმოხილვა“-ს."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"გასაგებია"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"არა, გმადლობთ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"დაიმალოს <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ჩართული"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"გამორთული"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"შეტყობინებების მართვის საშუალებების მეშვეობით, შეგიძლიათ განსაზღვროთ აპის შეტყობინებების მნიშვნელობის დონე 0-დან 5-მდე დიაპაზონში. \n\n"<b>"დონე 5"</b>" \n— შეტყობინებათა სიის თავში ჩვენება \n— სრულეკრანიანი რეჟიმის შეფერხების დაშვება \n— ეკრანზე ყოველთვის გამოჩენა \n\n"<b>"დონე 4"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე ყოველთვის გამოჩენა \n\n"<b>"დონე 3"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n\n"<b>"დონე 2"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n— ხმისა და ვიბრაციის აღკვეთა \n\n"<b>"დონე 1"</b>" \n— სრულეკრანიანი რეჟიმის შეფერხების აღკვეთა \n— ეკრანზე გამოჩენის აღკვეთა \n— ხმისა და ვიბრაციის აღკვეთა \n— ჩაკეტილი ეკრანიდან და სტატუსის ზოლიდან დამალვა \n— შეტყობინებათა სიის ბოლოში ჩვენება \n\n"<b>"დონე 0"</b>" \n— აპის ყველა შეტყობინების დაბლოკვა"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"შეტყობინებები"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"ამ შეტყობინებებს აღარ მიიღებთ."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-ის შეტყობინებები"</string>
+    <string name="min_importance" msgid="7559703098688382595">"დაბალი"</string>
+    <string name="low_importance" msgid="6891335321576225228">"საშუალო"</string>
+    <string name="default_importance" msgid="6400766013567512061">"მაღალი"</string>
+    <string name="high_importance" msgid="730741630855788381">"სასწრაფო"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ხმოვანი ან ვიზუალური შეფერხების გარეშე"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"უხმოდ ჩვენება"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ხმის გამოცემა"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ხმის გამოცემა და ეკრანზე გამოჩენა"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
     <string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> შეტყობინებების მართვის საშუალებები"</string>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index f5bf5f5..9faa5dc 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Бекіту экраны."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Параметрлер"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Шолу."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Әрекетті құлыптау экраны"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Жабу"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi өшірілді."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Жаю"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Жию"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Экран түйрелді"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Артқа\" және \"Шолу\" түймелерін басып тұрыңыз."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Экран босатылғанға дейін көрсетіліп тұрады. Оны босату үшін \"Кері\" түймесін басып тұрыңыз."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Түсіндім"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Жоқ, рақмет"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жасыру керек пе?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Қосулы"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Өшірулі"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Қуат хабарландыруының басқару элементтерімен қолданбаның хабарландырулары үшін 0-ден бастап 5-ке дейін маңыздылық деңгейін орнатуға болады. \n\n"<b>"5-деңгей"</b>" \n- Хабарландыру тізімінің ең басында көрсету \n- Толық экранға ашылуын рұқсат ету \n- Әрдайым қалқымалы хабарландыру түрінде көрсету \n\n"<b>"4-деңгей"</b>" \n- Толық экранға шығармау \n- Әрдайым қалқымалы хабарландыру түрінде көрсету \n\n"<b>"3-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n\n"<b>"2-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n- Ешқашан дыбыс және діріл шығармау \n\n"<b>"1-деңгей"</b>" \n- Толық экранға шығармау \n- Ешқашан қалқымалы хабарландыру түрінде көрсетпеу \n- Ешқашан дыбыс немесе діріл шығармау \n- Құлыпталған экраннан және күйін көрсету жолағынан жасыру \n- Хабарландыру тізімінің ең астында көрсету \n\n"<b>"0-деңгей"</b>" \n- Қолданбадағы барлық хабарландыруларға тыйым салу"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Хабарландырулар"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Сізге енді бұл хабарландырулар жіберілмейді."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> хабарландырулары"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Төмен"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Орташа"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Жоғары"</string>
+    <string name="high_importance" msgid="730741630855788381">"Шұғыл"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Дыбыссыз және визуалдық кедергісіз"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Дыбыссыз көрсету"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Дыбыстық сигнал беру"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Дыбыстық сигнал беру және экранға шығару"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
     <string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> хабарландыруларды басқару элементтері"</string>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index e160283..562727b 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ចាក់​សោ​អេក្រង់។"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ការកំណត់"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ទិដ្ឋភាព​។"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"អេក្រង់​ចាក់​សោ​លក្ខណៈ​ការងារ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"បិទ"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"បាន​បិទ​វ៉ាយហ្វាយ។"</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ពង្រីក"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"បង្រួម"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"អេក្រង់​ត្រូវ​បាន​ភ្ជាប់"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការដៅ។ សូម​សង្កត់​ប៊ូតុង​ថយ​ក្រោយ និង​ប៊ូតុង​ទិដ្ឋភាពរួម​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"វា​នឹង​នៅតែ​បង្ហាញ រហូត​ទាល់​តែ​អ្នក​ដក​ការ​ដៅ។ សូម​សង្កត់​ប៊ូតុង​ទិដ្ឋភាពរួម​​ឲ្យ​ជាប់ ដើម្បី​ដក​ការ​ដៅ។"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"យល់​ហើយ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ទេ អរគុណ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"លាក់ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"បើក"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"បិទ"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ជាមួយអង្គគ្រប់គ្រងការជូនដំណឹងថាមពល អ្នកអាចកំណត់កម្រិតសំខាន់ពី 0 ទៅ 5 សម្រាប់ការជូនដំណឹងរបស់កម្មវិធី។ \n\n"<b>"កម្រិត 5"</b>" \n- បង្ហាញនៅផ្នែកខាងលើបញ្ជីជូនដំណឹង \n- អនុញ្ញាតការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 4"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 3"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n\n"<b>"កម្រិត 2"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n- មិនបន្លឺសំឡេង ឬញ័រ \n\n"<b>"កម្រិត 1"</b>" \n- រារាំងការរំខានលើអេក្រង់ពេញ \n- លោតឡើងជានិច្ច \n- មិនបន្លឺសំឡេង ឬញ័រ \n- លាក់ពីអេក្រង់ចាក់សោ និងរបារស្ថានភាព \n- បង្ហាញនៅផ្នែកខាងក្រោមបញ្ជីជូនដំណឹង \n\n"<b>"កម្រិត 0"</b>" \n- រារាំងការជូនដំណឹងទាំងអស់ពីកម្មវិធី"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"ការ​ជូនដំណឹង"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"អ្នក​នឹង​មិន​ទទួល​បាន​ការ​ជូនដំណឹង​ទាំងនេះ​ទៀត​ទេ។"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ការ​ជូន​ដំណឹង​របស់ <xliff:g id="APP">%s</xliff:g> សម្រាប់"</string>
+    <string name="min_importance" msgid="7559703098688382595">"ទាប"</string>
+    <string name="low_importance" msgid="6891335321576225228">"មធ្យម"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ខ្ពស់"</string>
+    <string name="high_importance" msgid="730741630855788381">"បន្ទាន់"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"គ្មាន​សំឡេង ឬ​ការរំខាន​ដល់​ការ​មើល​ឡើយ"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"បង្ហាញ​ស្ងាត់ៗ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"បន្លឺ​សំឡេង"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"បន្លឺ​សំឡេង និង​លេច​ឡើង​នៅ​លើ​អេក្រង់"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ការកំណត់ច្រើនទៀត"</string>
     <string name="notification_done" msgid="5279426047273930175">"រួចរាល់"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"អង្គគ្រប់គ្រងការជូនដំណឹង <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 4073cc4..a0e2808 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ಲಾಕ್‌ ಪರದೆ."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ಸಮಗ್ರ ನೋಟ."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ಕೆಲಸದ ಲಾಕ್ ಪರದೆ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ಮುಚ್ಚು"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ವೈಫೈ ಆಫ್ ಮಾಡಲಾಗಿದೆ."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ವಿಸ್ತರಿಸು"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ಸಂಕುಚಿಸು"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ಪರದೆಯನ್ನು ಪಿನ್ ಮಾಡಲಾಗಿದೆ"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ ಹಾಗೂ ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕಿಸಿ."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ನೀವು ಅನ್‌ಪಿನ್ ಮಾಡುವವರೆಗೆ ಅದನ್ನು ವೀಕ್ಷಣೆಯಲ್ಲಿಡುತ್ತದೆ. ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅವಲೋಕನವನ್ನು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ತಿಳಿಯಿತು"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ಧನ್ಯವಾದಗಳು"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ಮರೆಮಾಡುವುದೇ?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ಆನ್"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ಆಫ್"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ಪವರ್ ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳ ಮೂಲಕ, ನೀವು ಅಪ್ಲಿಕೇಶನ್‌ಗಳ ಅಧಿಸೂಚನೆಗಳನ್ನು 0 ರಿಂದ 5 ರವರೆಗಿನ ಹಂತಗಳ ಪ್ರಾಮುಖ್ಯತೆಯನ್ನು ಹೊಂದಿಸಬಹುದು. \n\n"<b>"ಹಂತ 5"</b>" \n- ಮೇಲಿನ ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸಿ \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ಅನುಮತಿಸಿ \n- ಯಾವಾಗಲು ಇಣುಕು ನೋಟ \n\n"<b>"ಹಂತ 4"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಯಾವಾಗಲು ಇಣುಕು ನೋಟ\n\n"<b>"ಹಂತ 3"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n\n"<b>"ಹಂತ 2"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n- ಶಬ್ದ ಮತ್ತು ವೈಬ್ರೇಷನ್ ಎಂದಿಗೂ ಮಾಡಬೇಡಿ \n\n"<b>"ಹಂತ 1"</b>" \n- ಪೂರ್ಣ ಪರದೆ ಅಡಚಣೆಯನ್ನು ತಡೆಯಿರಿ \n- ಎಂದಿಗೂ ಇಣುಕು ನೋಟ ಬೇಡ \n- ಶಬ್ದ ಮತ್ತು ವೈಬ್ರೇಷನ್ ಎಂದಿಗೂ ಮಾಡಬೇಡಿ \n- ಸ್ಥಿತಿ ಪಟ್ಟಿ ಮತ್ತು ಲಾಕ್ ಪರದೆಯಿಂದ ಮರೆಮಾಡಿ \n- ಕೆಳಗಿನ ಅಧಿಸೂಚನೆ ಪಟ್ಟಿಯನ್ನು ತೋರಿಸಿ \n\n"<b>"ಹಂತ 0"</b>" \n- ಅಪ್ಲಿಕೇಶನ್‌ನಿಂದ ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ನಿರ್ಬಂಧಿಸಿ"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"ಅಧಿಸೂಚನೆಗಳು"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"ನೀವು ಇನ್ನು ಮುಂದೆ ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಪಡೆಯುವುದಿಲ್ಲ."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ಇದಕ್ಕೆ <xliff:g id="APP">%s</xliff:g> ಅಧಿಸೂಚನೆಗಳಿಗೆ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"ಕಡಿಮೆ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"ಮಧ್ಯಮ"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ಅಧಿಕ"</string>
+    <string name="high_importance" msgid="730741630855788381">"ತುರ್ತು"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ಯಾವುದೇ ಧ್ವನಿ ಅಥವಾ ದೃಶ್ಯ ಅಡಚಣೆಗಳಿಲ್ಲ"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"ಮೌನವಾಗಿ ತೋರಿಸಿ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ಧ್ವನಿ ಮಾಡಿ"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ಪರದೆಯ ಮೇಲೆ ಧ್ವನಿಮಾಡಿ ಮತ್ತು ಪಾಪ್ ಮಾಡಿ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="notification_done" msgid="5279426047273930175">"ಮುಗಿದಿದೆ"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅಧಿಸೂಚನೆ ನಿಯಂತ್ರಣಗಳು"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index abea176..de4e6ed 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"화면을 잠급니다."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"설정"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"최근 사용"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"업무용 잠금 화면"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"닫기"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi가 사용 중지되었습니다."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"펼치기"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"접기"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"화면 고정됨"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 뒤로 및 최근 사용을 길게 터치하세요."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"고정 해제할 때까지 계속 표시됩니다. 고정 해제하려면 최근 사용을 길게 터치하세요."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"확인"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"거부"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>을(를) 숨기시겠습니까?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"사용"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"사용 안함"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"전원 알림 컨트롤을 사용하면 앱 알림 관련 중요도를 0부터 5까지로 설정할 수 있습니다. \n\n"<b>"레벨 5"</b>" \n- 알림 목록 상단에 표시 \n- 전체 화면일 경우 알림 표시 허용 \n- 항상 엿보기 표시 \n\n"<b>"레벨 4"</b>" \n- 전체 화면에 알림 표시 금지 \n- 항상 엿보기 표시 \n\n"<b>"레벨 3"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n\n"<b>"레벨 2"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n- 소리나 진동으로 알리지 않음 \n\n"<b>"레벨 1"</b>" \n- 전체 화면에 알림 표시 금지 \n- 엿보기 표시 안함 \n- 소리나 진동으로 알리지 않음 \n- 잠금 화면 및 상태 표시줄에서 숨김 \n- 알림 목록 하단에 표시 \n\n"<b>"레벨 0"</b>" \n- 앱의 모든 알림 차단"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"알림"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"더 이상 다음의 알림을 받지 않습니다."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"다음 채널의 <xliff:g id="APP">%s</xliff:g> 알림"</string>
+    <string name="min_importance" msgid="7559703098688382595">"낮음"</string>
+    <string name="low_importance" msgid="6891335321576225228">"중간"</string>
+    <string name="default_importance" msgid="6400766013567512061">"높음"</string>
+    <string name="high_importance" msgid="730741630855788381">"긴급"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"소리나 시각적인 방해 없음"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"조용히 표시"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"소리로 알림"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"소리 및 화면 표시로 알림"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"설정 더보기"</string>
     <string name="notification_done" msgid="5279426047273930175">"완료"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> 알림 관리"</string>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 804511a..89790ee 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Кулпуланган экран."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Жөндөөлөр"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Көз жүгүртүү."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Жумуштун кулпуланган экраны"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Жабуу"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi өчүрүлдү."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Жайып көрсөтүү"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Жыйнап коюу"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Экран кадалган"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Артка\" жана \"Карап чыгуу\" баскычтарын басып, кармап туруңуз."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ал бошотулмайынча көрүнө берет. Бошотуу үчүн, \"Карап чыгуу\" баскычын басып, кармап туруңуз."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Түшүндүм"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Жок, рахмат"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> жашырылсынбы?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Күйүк"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Өчүк"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Бул функциянын жардамы менен ар бир колдонмо үчүн эскертменин маанилүүлүк деңгээлин 0дон 5ке чейин койсоңуз болот. \n\n"<b>"5-деңгээл"</b>" \n- Эскертмелер тизмесинин башында көрсөтүлсүн \n- Эскертмелер толук экранда көрсөтүлсүн \n- Калкып чыгуучу эскертмелерге уруксат берилсин \n\n"<b>"4-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге уруксат берилсин \n\n"<b>"3-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n\n"<b>"2-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n- Эч качан добуш чыгып же дирилдебесин \n\n"<b>"1-деңгээл"</b>" \n- Эскертмелер толук экранда көрсөтүлбөсүн \n- Калкып чыгуучу эскертмелерге тыюу салынсын \n- Эч качан добуш чыгып же дирилдебесин \n- Кулпуланган экрандан жана абал тилкесинен жашырылсын \n- Эскертмелер тизмесинин аягында көрсөтүлсүн \n\n"<b>"0-деңгээл"</b>" \n- Колдонмодон алынган бардык эскертмелер бөгөттөлсүн"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Эскертмелер"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Мындан ары бул эскертмелер сизге жөнөтүлбөйт."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> колдонмосунун төмөнкү каналга жөнөткөн эскертмелери"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Төмөн"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Орточо"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Жогору"</string>
+    <string name="high_importance" msgid="730741630855788381">"Шашылыш"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Добуш да чыгарбасын, экранда да көрсөтүлбөсүн"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Үнсүз көрсөтүлсүн"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Добуш чыгарсын"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Добуш менен экранга калкып чыксын"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
     <string name="notification_done" msgid="5279426047273930175">"Бүттү"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> эскертмесин башкаруу каражаттары"</string>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index 7eefe2e..da8a467 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ລັອກ​ໜ້າ​ຈໍ."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ການ​ຕັ້ງ​ຄ່າ"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"​ພາບ​ຮວມ."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ໜ້າຈໍລັອກວຽກ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ປິດ"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ປິດ Wi-Fi ແລ້ວ."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ຂະຫຍາຍ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ຫຍໍ້ລົງ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ປັກ​ໝຸດໜ້າ​ຈໍ​ແລ້ວ"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກມຸດ. ໃຫ້ແຕະປຸ່ມກັບຄືນ ແລະ ປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກມຸດ."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ນີ້ຈະສະແດງມັນໃນໜ້າຈໍຈົນກວ່າທ່ານຈະເຊົາປັກມຸດ. ໃຫ້ແຕະປຸ່ມພາບຮວມຄ້າງໄວ້ເພື່ອຍົກເລີກການປັກມຸດ."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ເຂົ້າໃຈແລ້ວ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ບໍ່, ຂອບໃຈ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ເຊື່ອງ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ຫຼື​ບໍ່?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ເປີດ"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ປິດ"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ດ້ວຍການຄວບຄຸມການແຈ້ງເຕືອນ, ທ່ານສາມາດຕັ້ງລະດັບຄວາມສຳຄັນຈາກ 0 ຮອດ 5 ໃຫ້ກັບການແຈ້ງເຕືອນແອັບໃດໜຶ່ງໄດ້. \n\n"<b>"ລະດັບ 5"</b>" \n- ສະແດງຢູ່ເທິງສຸດຂອງລາຍການແຈ້ງເຕືອນ \n- ອະນຸຍາດໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ແນມເບິ່ງທຸກເທື່ອ \n\n"<b>"ລະດັບ 4"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ແນມເບິ່ງທຸກເທື່ອ \n\n"<b>"ລະດັບ 3"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n\n"<b>"ລະດັບ 2"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n- ບໍ່ມີສຽງ ແລະ ບໍ່ມີການສັ່ນເຕືອນ \n\n"<b>"ລະດັບ 1"</b>" \n- ກັນບໍ່ໃຫ້ຂັດຈັງຫວະຕອນເປີດເຕັມຈໍ \n- ບໍ່ແນມເບິ່ງ \n- ບໍ່ມີສຽງ ແລະ ບໍ່ມີການສັ່ນເຕືອນ \n- ເຊື່ອງຈາກໜ້າຈໍລັອກ ແລະ ແຖບສະຖານະ \n- ສະແດງຢູ່ລຸ່ມສຸດຂອງລາຍການແຈ້ງເຕືອນ \n\n"<b>"ລະດັບ 0"</b>" \n- ປິດກັ້ນການແຈ້ງເຕືອນທັງໝົດຈາກແອັບ"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"ການແຈ້ງເຕືອນ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"ທ່ານຈະບໍ່ໄດ້ຮັບການແຈ້ງເຕືອນເຫຼົ່ານີ້ອີກຕໍ່ໄປ."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ການແຈ້ງເຕືອນ <xliff:g id="APP">%s</xliff:g> ສຳລັບ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"ຕໍ່າ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"ປານກາງ"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ສູງ"</string>
+    <string name="high_importance" msgid="730741630855788381">"ດ່ວນ"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ບໍ່ມີສຽງ ຫຼື ການລົບກວນໃນໜ້າຈໍ"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"ສະແດງແບບງຽບໆ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ເຮັດສຽງ"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ເຮັດສຽງດັງ ແລະ ສະແດງຂຶ້ນໃນໜ້າຈໍ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
     <string name="notification_done" msgid="5279426047273930175">"ສຳເລັດແລ້ວ"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"ການຄວບຄຸມການແຈ້ງເຕືອນ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 649e42a..b2ead25 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Užrakinimo ekranas."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Nustatymai"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Apžvalga."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Darbo profilio užrakinimo ekranas"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Uždaryti"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"„Wi-Fi“ ryšys išjungtas."</string>
@@ -444,10 +443,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Išskleisti"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sutraukti"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekranas prisegtas"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Atgal“ ir „Apžvalga“, kad atsegtumėte."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Tai bus rodoma, kol atsegsite. Palieskite ir palaikykite „Apžvalga“, kad atsegtumėte."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Supratau"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, ačiū"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Slėpti „<xliff:g id="TILE_LABEL">%1$s</xliff:g>“?"</string>
@@ -514,28 +511,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Įjungta"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Išjungta"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Naudodami pranešimų valdiklius galite nustatyti programos pranešimų svarbos lygį nuo 0 iki 5. \n\n"<b>"5 lygis"</b>" \n– Rodyti pranešimų sąrašo viršuje \n– Leisti pertraukti, kai veikia viso ekrano režimas \n– Visada rodyti pranešimus \n\n"<b>"4 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Visada rodyti pranešimus \n\n"<b>"3 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Niekada nerodyti pranešimų \n\n"<b>"2 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Niekada nerodyti pranešimų \n– Niekada neleisti garso ir nevibruoti \n\n"<b>"1 lygis"</b>" \n– Neleisti pertraukti viso ekrano režimo \n– Niekada nerodyti pranešimų \n– Niekada neleisti garso ir nevibruoti \n– Slėpti užrakinimo ekrane ir būsenos juostoje \n– Rodyti pranešimų sąrašo apačioje \n\n"<b>"0 lygis"</b>" \n– Blokuoti visus programos pranešimus"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Pranešimai"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Nebegausite šių pranešimų."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"„<xliff:g id="APP">%s</xliff:g>“ pranešimai, skirti"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nelabai svarbus"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Vidutiniškai svarbus"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Svarbus"</string>
+    <string name="high_importance" msgid="730741630855788381">"Skubus"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Neskambėti ir nepertraukti vaizdo"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Rodyti tyliai"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Skambėti"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Skambėti ir iššokti ekrane"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Daugiau nustatymų"</string>
     <string name="notification_done" msgid="5279426047273930175">"Atlikta"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"„<xliff:g id="APP_NAME">%1$s</xliff:g>“ pranešimų valdikliai"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index c230313..375b75e 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -186,8 +186,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Bloķēšanas ekrāns."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Iestatījumi"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pārskats."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Darba profila bloķēšanas ekrāns"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Aizvērt"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi ir izslēgts."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Izvērst"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Sakļaut"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrāns ir piesprausts"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties pogām Atpakaļ un Pārskats un turiet tās."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Šādi tas būs redzams līdz brīdim, kad to atspraudīsiet. Lai atspraustu, pieskarieties pogai Pārskats un turiet to."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Sapratu!"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nē, paldies"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vai paslēpt vienumu <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Ieslēgts"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Izslēgts"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Izmantojot barošanas paziņojumu vadīklas, varat lietotnes paziņojumiem iestatīt svarīguma līmeni (no 0 līdz 5). \n\n"<b>"5. līmenis"</b>" \n- Tiek rādīts paziņojumu saraksta augšdaļā \n- Tiek atļauta pilnekrāna režīma pārtraukšana \n- Ieskats vienmēr atļauts \n\n"<b>"4. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats vienmēr atļauts \n\n"<b>"3. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n\n"<b>"2. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n- Nav atļautas skaņas un vibrosignāls \n\n"<b>"1. līmenis"</b>" \n- Tiek novērsta pilnekrāna režīma pārtraukšana \n- Ieskats nav atļauts \n- Nav atļautas skaņas un vibrosignāls \n- Paziņojumi tiek paslēpti bloķēšanas ekrānā un statusa joslā \n- Paziņojumi tiek rādīti paziņojumu saraksta apakšdaļā \n\n"<b>"0. līmenis"</b>" \n- Visi lietotnes paziņojumi tiek bloķēti"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Paziņojumi"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Jūs vairs nesaņemsiet šos paziņojumus."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Lietotnes <xliff:g id="APP">%s</xliff:g> paziņojumi par"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Mazsvarīgs"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Vidēji svarīgs"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Ļoti svarīgs"</string>
+    <string name="high_importance" msgid="730741630855788381">"Steidzams"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez skaņas signāla vai vizuāla paziņojuma"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Rādīt bez skaņas signāla"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Atskaņot skaņas signālu"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Atskaņot skaņas signālu un īslaicīgi parādīt ekrānā"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Citi iestatījumi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gatavs"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> paziņojumu vadīklas"</string>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 110812b..7fccbe6 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Заклучи екран."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Поставки"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Краток преглед."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Работен заклучен екран"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Затвори"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi е исклученo."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Прошири"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Собери"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екранот е прикачен"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Назад“ и „Краток преглед“ за откачување."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ќе се гледа сѐ додека не го откачите. Допрете и држете „Краток преглед“ за откачување."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Сфатив"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, фала"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сокриј <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Вклучено"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Исклучено"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Со контролите за известувањата за напојување, може да поставите ниво на важност од 0 до 5 за известувањата на која било апликација. \n\n"<b>"Ниво 5"</b>" \n- Прикажувај на врвот на списокот со известувања \n- Дозволи прекин во цел екран \n- Секогаш користи појавување \n\n"<b>"Ниво 4"</b>" \n- Спречи прекин во цел екран \n- Секогаш користи појавување \n\n"<b>"Ниво 3"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n\n"<b>"Ниво 2"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n- Без звук и вибрации \n\n"<b>"Ниво 1"</b>" \n- Спречи прекин во цел екран \n- Без појавување \n- Без звук и вибрации \n- Сокриј од заклучен екран и статусна лента \n- Прикажувај на дното на списокот со известувања \n\n"<b>"Ниво 0"</b>" \n- Блокирај ги сите известувања од апликацијата"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Известувања"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Веќе нема да ги добивате овие известувања."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Известувања од <xliff:g id="APP">%s</xliff:g> за"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Ниско"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Средно"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Високо"</string>
+    <string name="high_importance" msgid="730741630855788381">"Итно"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без звук или визуелен прекин"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Прикажи тивко"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Испушти звук"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Испушти звук и прикажи го на екранот"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Повеќе поставки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроли за известувања на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 4c4a99b..4e64a74 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ലോക്ക് സ്‌ക്രീൻ."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ക്രമീകരണം"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"കാഴ്ച."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ഔദ്യോഗിക ലോക്ക് സ്ക്രീൻ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"അടയ്‌ക്കുക"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"വൈഫൈ ഓഫാക്കി."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"വികസിപ്പിക്കുക"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ചുരുക്കുക"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"സ്‌ക്രീൻ പിൻ ചെയ്‌തു"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'തിരികെ\', \'ചുരുക്കവിവരണം\' എന്നിവ സ്‌പർശിച്ച് പിടിക്കുക."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"നിങ്ങൾ അൺപിൻ ചെയ്യുന്നതുവരെ ഇത് കാണുന്ന വിധത്തിൽ നിലനിർത്തും. അൺപിൻ ചെയ്യാൻ \'ചുരുക്കവിവരണം\' സ്‌പർശിച്ച് പിടിക്കുക."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"മനസ്സിലായി"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"വേണ്ട, നന്ദി"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> എന്നത് മറയ്‌ക്കണോ?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ഓൺ"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ഓഫ്"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"പവർ അറിയിപ്പ് നിയന്ത്രണം ഉപയോഗിച്ച്, ഒരു ആപ്പിനായുള്ള അറിയിപ്പുകൾക്ക് 0 മുതൽ 5 വരെയുള്ള പ്രാധാന്യ ലെവലുകളിലൊന്ന് നിങ്ങൾക്ക് സജ്ജമാക്കാവുന്നതാണ്. \n\n"<b>"ലെവൽ 5"</b>" \n- അറിയിപ്പ് ലിസ്റ്റിന്റെ മുകളിൽ കാണിക്കുക \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം അനുവദിക്കുക \n- എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക \n\n"<b>"ലെവൽ 4"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- എല്ലായ്പ്പോഴും ദൃശ്യമാക്കുക \n\n"<b>"ലെവൽ 3"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും സൃശ്യമാക്കരുത് \n\n"<b>"ലെവൽ 2"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും ദൃശ്യമാക്കരുത് \n- ഒരിക്കലും ശബ്ദവും വൈബ്രേഷനും ഉണ്ടാക്കരുത് \n\n"<b>"ലെവൽ 1"</b>" \n- മുഴുവൻ സ്ക്രീൻ തടസ്സം തടയുക \n- ഒരിക്കലും ദൃശ്യമാക്കരുത് \n- ഒരിക്കലും ശബ്ദവും വൈബ്രേഷനും ഉണ്ടാക്കരുത് \n- ലോക്ക് സ്ക്രീനിൽ നിന്നും സ്റ്റാറ്റസ് ബാറിൽ നിന്നും മറയ്ക്കുക \n- അറിയിപ്പ് ലിസ്റ്റിന്റെ അടിയിൽ കാണിക്കുക \n\n"<b>"ലെവൽ 0"</b>" \n- ആപ്പിൽ നിന്നുള്ള എല്ലാ അറിയിപ്പുകളും ബ്ലോക്കുചെയ്യുക"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"അറിയിപ്പുകൾ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"നിങ്ങൾക്ക് ഈ അറിയിപ്പുകൾ ഇനിയങ്ങോട്ട് ലഭിക്കില്ല."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ഇനിപ്പറയുന്നതിനുള്ള <xliff:g id="APP">%s</xliff:g> അറിയിപ്പുകൾ:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"കുറഞ്ഞ പ്രാധാന്യം"</string>
+    <string name="low_importance" msgid="6891335321576225228">"ഇടത്തരം പ്രാധാന്യം"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ഉയർന്ന പ്രാധാന്യം"</string>
+    <string name="high_importance" msgid="730741630855788381">"അടിയന്തിര പ്രാധാന്യം"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ശബ്ദപരമോ ദൃശ്യപരമോ ആയ തടസ്സമില്ല"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"നിശബ്ദമായി കാണിക്കുക"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ശബ്ദമുണ്ടാക്കുക"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ശബ്ദമുണ്ടാക്കുക, സ്ക്രീനിൽ കാണിക്കുക"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"കൂടുതൽ ക്രമീകരണം"</string>
     <string name="notification_done" msgid="5279426047273930175">"പൂർത്തിയായി"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> അറിയിപ്പ് നിയന്ത്രണങ്ങൾ"</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 0433950..3c12896 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -183,8 +183,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Дэлгэц түгжих."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Тохиргоо"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Тойм"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ажлын түгжигдсэн дэлгэц"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Хаах"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi унтраасан."</string>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index fef7d65..7fc127a 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"लॉक स्क्रीन."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"सेटिंग्ज"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"विहंगावलोकन."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"कार्य लॉक स्क्रीन"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"बंद करा"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi बंद झाले."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तृत करा"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संकुचित करा"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"स्क्रीन पिन केलेली आहे"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"आपण अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी परत आणि विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"आपण अनपिन करेर्यंत हे यास दृश्यामध्ये ठेवते. अनपिन करण्‍यासाठी विहंगावलोकनास स्पर्श करा आणि धरून ठेवा."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"समजले"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"नाही धन्यवाद"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> लपवायचे?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"चालू"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"बंद"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"उर्जा सूचना नियंत्रणांसह, आपण अॅपच्या सूचनांसाठी महत्त्व स्तर 0 ते 5 पर्यंत सेट करू शकता. \n\n"<b>"स्तर 5"</b>" \n- सूचना सूचीच्या शीर्षस्थानी दर्शवा \n- पूर्ण स्क्रीन व्यत्ययास अनुमती द्या \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 4"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- नेहमी डोकावून पहा \n\n"<b>"स्तर 3"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n\n"<b>"स्तर 2"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा कंपन करू नका \n\n"<b>"स्तर 1"</b>" \n- पूर्ण स्क्रीन व्यत्ययास प्रतिबंधित करा \n- कधीही डोकावून पाहू नका \n- कधीही ध्वनी किंवा कंपन करू नका \n- लॉक स्क्रीन आणि स्टेटस बार मधून लपवा \n- सूचना सूचीच्या तळाशी दर्शवा \n\n"<b>"स्तर 0"</b>" \n- अॅपमधील सर्व सूचना अवरोधित करा"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"सूचना"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"आपल्याला यापुढे या सूचना प्राप्त होणार नाहीत."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"यासाठी <xliff:g id="APP">%s</xliff:g> सूचना"</string>
+    <string name="min_importance" msgid="7559703098688382595">"निम्न"</string>
+    <string name="low_importance" msgid="6891335321576225228">"मध्‍यम"</string>
+    <string name="default_importance" msgid="6400766013567512061">"सर्वाधिक"</string>
+    <string name="high_importance" msgid="730741630855788381">"त्वरित"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"कोणताही ध्वनी किंवा व्हिज्युअल व्यत्यय नाही"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"शांतपणे दर्शवा"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ध्वनी करा"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ध्वनी करा आणि स्क्रीनवर पॉप करा"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
     <string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> सूचना नियंत्रणे"</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index d6c90a9..2069959 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Kunci skrin."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Tetapan"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Ikhtisar."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Skrin kunci kerja"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Tutup"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi dimatikan."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Kembangkan"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Runtuhkan"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skrin telah disemat"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Kembali dan Ikhtisar untuk menyahsemat."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Tindakan ini memastikan skrin kelihatan sehingga anda menyahsemat. Sentuh &amp; tahan Ikhtisar untuk menyahsemat."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Faham"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Tidak"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Sembunyikan <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Hidup"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Mati"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Dengan kawalan pemberitahuan berkuasa, anda boleh menetapkan tahap kepentingan dari 0 hingga 5 untuk pemberitahuan apl. \n\n"<b>"Tahap 5"</b>" \n- Tunjukkan pada bahagian atas senarai pemberitahuan \n- Benarkan gangguan skrin penuh \n- Sentiasa intai \n\n"<b>"Tahap 4"</b>" \n- Halang gangguan skrin penuh \n- Sentiasa intai \n\n"<b>"Tahap 3"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n\n"<b>"Tahap 2"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n- Jangan berbunyi dan bergetar \n\n"<b>"Tahap 1"</b>" \n- Halang gangguan skrin penuh \n- Jangan intai \n- Jangan berbunyi atau bergetar \n- Sembunyikan daripada skrin kunci dan bar status \n- Tunjukkan di bahagian bawah senarai pemberitahuan \n\n"<b>"Tahap 0"</b>" \n- Sekat semua pemberitahuan daripada apl"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Pemberitahuan"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Anda tidak akan menerima pemberitahuan ini lagi."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Pemberitahuan <xliff:g id="APP">%s</xliff:g> untuk"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Rendah"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Sederhana"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Tinggi"</string>
+    <string name="high_importance" msgid="730741630855788381">"Segera"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Tiada gangguan bunyi atau visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Tunjukkan secara senyap"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Berbunyi"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Berbunyi dan paparkan pada skrin"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
     <string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kawalan pemberitahuan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 17eeacf..db6edad 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"မျက်နှာပြင် သော့ပိတ်ရန်"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ဆက်တင်များ"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ခြုံကြည့်မှု။"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"အလုပ်သုံး လော့ခ်မျက်နှာပြင်"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ပိတ်ရန်"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>။"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ကြိုးမဲ့ ပိတ်ထား။"</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"တိုးချဲ့ရန်"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ခေါက်သိမ်းရန်..."</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"မျက်နှာပြင် ပင်ထိုးပြီးပါပြီ"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"သင်ပင်မဖြုတ်မခြင်း ၎င်းကို ပြသထားပါမည်။ ပင်ဖြုတ်ရန် Back နှင့် Overview ကို ထိ၍ဖိထားပါ။"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"သင်ပင်မဖြုတ်မချင်း ၎င်းကိုပြသထားပါမည်။ ပင်ဖြုတ်ရန် Overview ကိုထိပြီး ဖိထားပါ။"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"အဲဒါ ရပါပြီ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"မလိုတော့ပါ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> ဝှက်မည်လား?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ဖွင့်ပါ"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ပိတ်ပါ"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ပါဝါအကြောင်းကြားချက် ထိန်းချုပ်မှုများကိုအသုံးပြုပြီး အက်ပ်တစ်ခု၏ အကြောင်းကြားချက် အရေးပါမှု ၀ မှ ၅ အထိသတ်မှတ်ပေးနိုင်သည်။ \n\n"<b>"အဆင့် ၅"</b>" \n- အကြောင်းကြားချက်စာရင်း၏ ထိပ်ဆုံးတွင် ပြသည် \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်းကို ခွင့်ပြုသည် \n- အမြဲတမ်း ခေတ္တပြပါမည် \n\n"<b>"အဆင့် ၄"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- အမြဲတမ်း ခေတ္တပြပါမည် \n\n"<b>"အဆင့် ၃"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n\n"<b>"အဆင့် ၂"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n- အသံမြည်ခြင်းနှင့် တုန်ခါခြင်းများ ဘယ်တော့မှ မပြုလုပ်ပါ \n\n"<b>"အဆင့် ၁"</b>" \n- မျက်နှာပြင်အပြည့် ကြားဖြတ်ဖော်ပြခြင်း မရှိစေရန် ကာကွယ်ပေးသည် \n- ဘယ်တော့မှ ခေတ္တပြခြင်း မရှိပါ \n- အသံမြည်ခြင်းနှင့် တုန်ခါခြင်းများ ဘယ်တော့မှ မပြုလုပ်ပါ \n- လော့ခ်ချထားသည့် မျက်နှာပြင်နှင့် အခြေအနေဘားတန်းတို့တွင် မပြပါ \n- အကြောင်းကြားချက်စာရင်း အောက်ဆုံးတွင်ပြသည် \n\n"<b>"အဆင့် ၀"</b>" \n- အက်ပ်မှ အကြောင်းကြားချက်များ အားလုံးကို ပိတ်ဆို့သည်"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"အကြောင်းကြားချက်များ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"သင်သည် ဤအကြောင်းကြားချက်များကို လက်ခံရရှိတော့မည် မဟုတ်ပါ။"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ဤအရာအတွက် <xliff:g id="APP">%s</xliff:g> အကြောင်းကြားချက်များ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"အရေးသိပ်မကြီးပါ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"အတော်အသင့်"</string>
+    <string name="default_importance" msgid="6400766013567512061">"အရေးကြီးသည်"</string>
+    <string name="high_importance" msgid="730741630855788381">"အရေးပေါ်"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"မည်သည့်အသံ သို့မဟုတ် ရုပ်ပုံ ကြားဝင်နှောင့်ယှက်ခြင်း မရှိပါ"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"တိတ်တဆိတ်ပြပါ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"အသံဖွင့်ပါ"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"အသံဖွင့်၍ မျက်နှာပြင်ပေါ်တွင် ပြပါ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"နောက်ထပ် ဆက်တင်များ"</string>
     <string name="notification_done" msgid="5279426047273930175">"ပြီးပါပြီ"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> အကြောင်းကြားချက် ထိန်းချုပ်မှုများ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index b5f915d..e5b94bd 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Låseskjerm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Innstillinger"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Oversikt."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Låseskjerm for arbeid"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Lukk"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi er slått av."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utvid"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Skjul"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skjermen er låst"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Tilbake og Oversikt for å løsne den."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"På denne måten blir skjermen synlig frem til du løsner den. Trykk og hold inne Oversikt for å løsne den."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Skjønner"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nei takk"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vil du skjule <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"På"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Av"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Med effektive varselinnstillinger kan du angi viktighetsnivåer fra 0 til 5 for appvarsler. \n\n"<b>"Nivå 5"</b>" \n– Vis øverst på varsellisten \n– Tillat forstyrrelser ved fullskjermmodus \n– Vis alltid raskt \n\n"<b>"Nivå 4"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis alltid raskt \n\n"<b>"Nivå 3"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri raskt \n\n"<b>"Nivå 2"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri fort \n– Tillat aldri lyder eller vibrering \n\n"<b>"Nivå 1"</b>" \n– Forhindre forstyrrelser ved fullskjermmodus \n– Vis aldri raskt \n– Tillat aldri lyder eller vibrering \n– Skjul fra låseskjermen og statusfeltet \n– Vis nederst på varsellisten \n\n"<b>"Nivå 0"</b>" \n– Blokkér alle varsler fra appen"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Varsler"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Du får ikke disse varslene lenger."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-varsler for"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Lav"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Middels"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Høy"</string>
+    <string name="high_importance" msgid="730741630855788381">"Haster"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ingen lyd eller visuell forstyrrelse"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Vis uten lyd"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Lag lyd"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Lag lyd og vis i forgrunnen"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Flere innstillinger"</string>
     <string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Varselinnstillinger for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 0d20b04..893f638 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"स्क्रीन बन्द गर्नुहोस्।"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"सेटिङहरू"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"सारांश।"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"कार्य प्रोफाइलको लक स्क्रिन"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"बन्द गर्नुहोस्"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>।"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi बन्द गरियो।"</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"विस्तार गर्नुहोस्"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"संक्षिप्त पार्नुहोस्"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"पर्दा राखेका छ"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न पछाडि र परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"तपाईंले अनपिन नगरेसम्म यसले त्यसलाई दृश्यमा कायम राख्छ। अनपिन गर्न परिदृश्य बटनलाई छोइराख्नुहोस्।"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"बुझेँ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"धन्यवाद पर्दैन"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"लुकाउनुहुन्छ <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"सक्रिय"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"निष्क्रिय"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"सशक्त सूचना नियन्त्रणहरू मार्फत तपाईँ अनुप्रयाेगका सूचनाहरूका लागि ० देखि ५ सम्मको महत्व सम्बन्धी स्तर सेट गर्न सक्नुहुन्छ। \n\n"<b>"स्तर ५"</b>" \n- सूचनाको सूचीको माथिल्लो भागमा देखाउने \n- पूर्ण स्क्रिनमा अवरोधका लागि अनुमति दिने \n- सधैँ चियाउने \n\n"<b>"स्तर ४"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- सधैँ चियाउने \n\n"<b>"स्तर ३"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n\n"<b>"स्तर २"</b>" \n- पूर्ण स्क्रिनमा अवरोधलाई रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने र कम्पन नगर्ने \n\n"<b>"स्तर १"</b>" \n- पूर्ण स्क्रिनमा अवरोध रोक्ने \n- कहिल्यै नचियाउने \n- कहिल्यै पनि आवाज ननिकाल्ने वा कम्पन नगर्ने \n- लक स्क्रिन र वस्तुस्थिति पट्टीबाट लुकाउने \n- सूचनाको सूचीको तल्लो भागमा देखाउने \n\n"<b>"स्तर ०"</b>" \n- अनुप्रयोगका सबै सूचनाहरूलाई रोक्ने"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"सूचनाहरू"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"तपाईंले अबदेखि यी सूचनाहरू प्राप्त गर्नुहुने छैन।"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"निम्न कुराका लागि <xliff:g id="APP">%s</xliff:g> का सूचनाहरू"</string>
+    <string name="min_importance" msgid="7559703098688382595">"न्यून"</string>
+    <string name="low_importance" msgid="6891335321576225228">"मध्यम"</string>
+    <string name="default_importance" msgid="6400766013567512061">"उच्च"</string>
+    <string name="high_importance" msgid="730741630855788381">"जरुरी"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"कुनै आवाज ननिकाल्ने वा दृश्य सम्बन्धी अवरोध नपुर्याउने"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"मौन रूपमा देखाउने"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"आवाज निकाल्ने"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"आवाज निकाल्ने र स्क्रिनमा पपअप देखाउने"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"थप सेटिङहरू"</string>
     <string name="notification_done" msgid="5279426047273930175">"सम्पन्‍न भयो"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> का सूचनाका लागि नियन्त्रणहरू"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 9c6fbbd..df1f97b 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Vergrendelingsscherm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Instellingen"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Overzicht."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Vergrendelingsscherm voor werk"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Sluiten"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi uitgeschakeld."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Uitvouwen"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Samenvouwen"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Scherm is vastgezet"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Terug en Overzicht en houd deze vast om het scherm los te maken."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Het scherm blijft zichtbaar totdat je het losmaakt. Tik op Overzicht en houd dit vast om het scherm los te maken."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ik snap het"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nee, bedankt"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> verbergen?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Aan"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Uit"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Met beheeropties voor meldingen met betrekking tot stroomverbruik kun je een belangrijkheidsniveau van 0 tot 5 instellen voor de meldingen van een app. \n\n"<b>"Niveau 5"</b>" \n- Boven aan de lijst met meldingen weergeven \n- Onderbreking op volledig scherm toestaan \n- Altijd korte weergave \n\n"<b>"Niveau 4"</b>" \n- Geen onderbreking op volledig scherm \n- Altijd korte weergave \n\n"<b>"Niveau 3"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n\n"<b>"Niveau 2"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n\n"<b>"Niveau 1"</b>" \n- Geen onderbreking op volledig scherm \n- Nooit korte weergave \n- Nooit geluid laten horen of trillen \n- Verbergen op vergrendelingsscherm en statusbalk \n- Onder aan de lijst met meldingen weergeven \n\n"<b>"Niveau 0"</b>" \n- Alle meldingen van de app blokkeren"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Meldingen"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Je ontvangt deze meldingen niet meer."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>-meldingen voor"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Laag"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Gemiddeld"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Hoog"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgent"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Geen geluid of visuele onderbreking"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Zonder geluid weergeven"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Geluid laten horen"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Geluid laten horen en op het scherm weergeven"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Meer instellingen"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gereed"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Beheeropties voor <xliff:g id="APP_NAME">%1$s</xliff:g>-meldingen"</string>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 3f0915b..763ee1f 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ਲੌਕ ਸਕ੍ਰੀਨ।"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ਸੈਟਿੰਗਾਂ"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ਰੂਪ-ਰੇਖਾ।"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"ਕਾਰਜ-ਸਥਾਨ ਲੌਕ ਸਕ੍ਰੀਨ"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ਬੰਦ ਕਰੋ"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>।"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi ਬੰਦ ਕੀਤਾ।"</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"ਨਸ਼ਟ ਕਰੋ"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"ਸਕ੍ਰੀਨ ਪਿੰਨ ਕੀਤੀ"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"ਇਹ ਇਸ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿੰਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਪਿੱਛੇ\' ਅਤੇ \'ਰੂਪ-ਰੇਖਾ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"ਇਹ ਇਸ ਨੂੰ ਤਦ ਤੱਕ ਦ੍ਰਿਸ਼ ਵਿੱਚ ਰੱਖਦਾ ਹੈ ਜਦ ਤੱਕ ਤੁਸੀਂ ਅਨਪਿੰਨ ਨਹੀਂ ਕਰਦੇ। ਅਨਪਿੰਨ ਕਰਨ ਲਈ \'ਰੂਪ-ਰੇਖਾ\' ਨੂੰ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ਸਮਝ ਲਿਆ"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"ਨਹੀਂ ਧੰਨਵਾਦ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"ਕੀ <xliff:g id="TILE_LABEL">%1$s</xliff:g> ਨੂੰ ਲੁਕਾਉਣਾ ਹੈ?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ਚਾਲੂ"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ਬੰਦ"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ਪਾਵਰ ਸੂਚਨਾ ਕੰਟਰੋਲਾਂ ਨਾਲ, ਤੁਸੀਂ ਕਿਸੇ ਐਪ ਦੀਆਂ ਸੂਚਨਾਵਾਂ ਲਈ ਮਹੱਤਤਾ ਪੱਧਰ ਨੂੰ 0 ਤੋਂ 5 ਤੱਕ ਸੈੱਟ ਕਰ ਸਕਦੇ ਹੋ। \n\n"<b>"ਪੱਧਰ 5"</b>" \n- ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਦੀ ਆਗਿਆ ਦਿਓ \n- ਹਮੇਸ਼ਾਂ ਝਲਕ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 4"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਹਮੇਸ਼ਾਂ ਝਲਕ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 3"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 2"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਵਿਖਾਓ \n- ਕਦੇ ਵੀ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਾ ਕਰੋ \n\n"<b>"ਪੱੱਧਰ 1"</b>" \n- ਪੂਰੀ ਸਕ੍ਰੀਨ ਰੁਕਾਵਟ ਨੂੰ ਰੋਕੋ \n- ਕਦੇ ਝਲਕ ਨਾ ਵਿਖਾਓ \n- ਕਦੇ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਾ ਕਰੋ \n- ਲੌਕ ਸਕ੍ਰੀਨ ਅਤੇ ਸਥਿਤੀ ਪੱਟੀ ਤੋਂ ਲੁਕਾਓ \n- ਸੂਚਨਾ ਸੂਚੀ ਦੇ ਹੇਠਾਂ ਵਿਖਾਓ \n\n"<b>"ਪੱਧਰ 0"</b>" \n- ਐਪ ਤੋਂ ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਬਲੌਕ ਕਰੋ"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"ਸੂਚਨਾਵਾਂ"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"ਤੁਸੀਂ ਹੁਣ ਇਹ ਸੂਚਨਾਵਾਂ ਪ੍ਰਾਪਤ ਨਹੀਂ ਕਰੋਂਗੇ।"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"ਇਸ ਦੇ ਲਈ <xliff:g id="APP">%s</xliff:g> ਸੂਚਨਾਵਾਂ"</string>
+    <string name="min_importance" msgid="7559703098688382595">"ਘੱਟ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"ਔਸਤ"</string>
+    <string name="default_importance" msgid="6400766013567512061">"ਉੱਚ"</string>
+    <string name="high_importance" msgid="730741630855788381">"ਜ਼ਰੂਰੀ"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਦ੍ਰਿਸ਼ਟਾਂਤਕ ਰੁਕਾਵਟ ਨਹੀਂ"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"ਚੁੱਪਚਾਪ ਵਿਖਾਓ"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ਧੁਨੀ ਵਜਾਓ"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ਧੁਨੀ ਵਜਾਓ ਅਤੇ ਸਕ੍ਰੀਨ \'ਤੇ ਵਿਖਾਓ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
     <string name="notification_done" msgid="5279426047273930175">"ਹੋ ਗਿਆ"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਸੂਚਨਾ ਕੰਟਰੋਲ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index abaf4bc..456ed81 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Ekran blokady."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ustawienia"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Przegląd."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ekran blokady wyświetlany podczas działania"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zamknij"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi wyłączone."</string>
@@ -444,10 +443,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozwiń"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Zwiń"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran jest przypięty"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Wstecz oraz Przegląd."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran będzie widoczny, dopóki go nie odepniesz. Aby to zrobić, kliknij i przytrzymaj Przegląd."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nie, dziękuję"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ukryć <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -514,28 +511,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Wł."</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Wył."</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Dzięki zaawansowanym ustawieniom możesz określić poziom ważności powiadomień z aplikacji w skali od 0 do 5. \n\n"<b>"Poziom 5"</b>" \n– Pokazuj u góry listy powiadomień \n– Zezwalaj na powiadomienia na pełnym ekranie \n– Zawsze pokazuj podgląd \n\n"<b>"Poziom 4"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Zawsze pokazuj podgląd \n\n"<b>"Poziom 3"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n\n"<b>"Poziom 2"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n– NIgdy nie powiadamiaj dźwiękiem ani wibracjami \n\n"<b>"Poziom 1"</b>" \n– Wyłącz powiadomienia na pełnym ekranie \n– Nigdy nie pokazuj podglądu \n– NIgdy nie powiadamiaj dźwiękiem ani wibracjami \n– Ukrywaj na ekranie blokady i pasku stanu \n– Pokazuj u dołu listy powiadomień \n\n"<b>"Poziom 0"</b>" \n– Blokuj wszystkie powiadomienia aplikacji"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Powiadomienia"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Nie będziesz już otrzymywać tych powiadomień."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Powiadomienia aplikacji <xliff:g id="APP">%s</xliff:g>"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Niska"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Średnia"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Wysoka"</string>
+    <string name="high_importance" msgid="730741630855788381">"Pilna"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Brak dźwięku i komunikatów wizualnych"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Pokazuj dyskretnie"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Sygnalizacja dźwiękiem"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Sygnalizacja dźwiękiem i wyświetlenie komunikatu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> – ustawienia powiadomień"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 70618c9..e2a1818 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Tela de bloqueio."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Configurações"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Visão geral."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Tela de bloqueio de trabalho"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Fechar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"O Wi-Fi foi desativado."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Recolher"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A tela está fixada"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ela é mantida à vista até que seja liberada. Toque em Visão geral e mantenha essa opção pressionada para liberar."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Ativado"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desativado"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Com controles de ativação de notificações, é possível definir o nível de importância de 0 a 5 para as notificações de um app. \n\n"<b>"Nível 5"</b>" \n- Exibir na parte superior da lista de notificações \n- Permitir interrupção em tela cheia \n- Sempre exibir \n\n"<b>"Nível 4"</b>" \n- Impedir interrupções em tela cheia \n- Sempre exibir \n\n"<b>"Nível 3"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n\n"<b>"Nível 2"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n- Ocultar da tela de bloqueio e barra de status \n- Exibir na parte inferior da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações do app"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Você deixará de receber essas notificações."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificações do app <xliff:g id="APP">%s</xliff:g> para"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baixa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Média"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Sem som ou interrupção visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir som"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir som e exibir na tela"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 7102c64..f90e1ee 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Ecrã de bloqueio."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Definições"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Visão geral."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ecrã de bloqueio de trabalho"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Fechar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi desligado."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Reduzir"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"O ecrã está fixado"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Anterior e em Vista geral para soltar."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Esta opção mantém o item visível até o soltar. Toque sem soltar em Vista geral para soltar."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Compreendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Pretende ocultar <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Ativado"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desativado"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Com os controlos de notificações do consumo de energia, pode definir um nível de importância de 0 a 5 para as notificações de aplicações. \n\n"<b>"Nível 5"</b>" \n- Mostrar no início da lista de notificações \n- Permitir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre \n\n"<b>"Nível 4"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Aparecer rapidamente sempre\n\n"<b>"Nível 3"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n\n"<b>"Nível 2"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir a interrupção do ecrã inteiro \n- Nunca aparecer rapidamente \n- Nunca tocar nem vibrar \n- Ocultar do ecrã de bloqueio e da barra de estado \n- Mostrar no fim da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações da aplicação"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Já não recebe estas notificações."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificações da aplicação <xliff:g id="APP">%s</xliff:g> para"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baixa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Média"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Sem interrupção sonora ou visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar silenciosamente"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir som"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir som e aparecer no ecrã"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais definições"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controlos de notificações do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 70618c9..e2a1818 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Tela de bloqueio."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Configurações"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Visão geral."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Tela de bloqueio de trabalho"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Fechar"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"O Wi-Fi foi desativado."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Expandir"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Recolher"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"A tela está fixada"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ela é mantida à vista até que seja liberada. Toque em Voltar e em Visão geral e mantenha essas opções pressionadas para liberar."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ela é mantida à vista até que seja liberada. Toque em Visão geral e mantenha essa opção pressionada para liberar."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Entendi"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Não, obrigado"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Esconder <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Ativado"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Desativado"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Com controles de ativação de notificações, é possível definir o nível de importância de 0 a 5 para as notificações de um app. \n\n"<b>"Nível 5"</b>" \n- Exibir na parte superior da lista de notificações \n- Permitir interrupção em tela cheia \n- Sempre exibir \n\n"<b>"Nível 4"</b>" \n- Impedir interrupções em tela cheia \n- Sempre exibir \n\n"<b>"Nível 3"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n\n"<b>"Nível 2"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n\n"<b>"Nível 1"</b>" \n- Impedir interrupções em tela cheia \n- Nunca exibir \n- Nunca emitir som ou vibrar \n- Ocultar da tela de bloqueio e barra de status \n- Exibir na parte inferior da lista de notificações \n\n"<b>"Nível 0"</b>" \n- Bloquear todas as notificações do app"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificações"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Você deixará de receber essas notificações."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificações do app <xliff:g id="APP">%s</xliff:g> para"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Baixa"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Média"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Alta"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgente"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Sem som ou interrupção visual"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Mostrar de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Emitir som"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Emitir som e exibir na tela"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Controles de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 2544849..8dca94e 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -188,8 +188,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Ecranul de blocare."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Setări"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Vizualizare generală"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ecran de blocare pentru serviciu"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Închideți"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Conexiunea prin Wi-Fi este dezactivată."</string>
@@ -444,10 +443,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Extindeți"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Restrângeți"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ecranul este fixat"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunile Înapoi și Recente pentru a anula fixarea."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Astfel rămâne afișat până anulați fixarea. Atingeți lung opțiunea Recente pentru a anula fixarea."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Am înțeles"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nu, mulțumesc"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ascundeți <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -514,28 +511,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Activate"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Dezactivate"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Folosind comenzile de gestionare a notificărilor, puteți să setați un nivel de importanță de la 0 la 5 pentru notificările unei aplicații. \n\n"<b>"Nivelul 5"</b>" \n– Se afișează la începutul listei de notificări \n– Se permite întreruperea pe ecranul complet \n– Se afișează întotdeauna scurt \n\n"<b>"Nivelul 4"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Se afișează întotdeauna scurt \n\n"<b>"Nivelul 3"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n\n"<b>"Nivelul 2"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n– Nu se emit sunete și nu vibrează niciodată \n\n"<b>"Nivelul 1"</b>" \n– Se împiedică întreruperea pe ecranul complet \n– Nu se afișează niciodată scurt \n– Nu se emit sunete și nu vibrează niciodată \n– Se ascunde în ecranul de blocare și în bara de stare \n– Se afișează la finalul listei de notificări \n\n"<b>"Nivelul 0"</b>" \n– Se blochează toate notificările din aplicație"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Notificări"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Nu veți mai primi aceste notificări."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Notificări <xliff:g id="APP">%s</xliff:g> pentru"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Scăzută"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Medie"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Ridicată"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgentă"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Fără sunet sau întrerupere vizuală"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Se afișează fără sunet"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Se emite un sunet"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Se emite un sunet și se evidențiază pe ecran"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mai multe setări"</string>
     <string name="notification_done" msgid="5279426047273930175">"Terminat"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Opțiuni privind notificările pentru <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index aa7695a..9e046ed 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Заблокированный экран."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Настройки"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Обзор."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Заблокировано"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Закрыть"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Модуль Wi-Fi отключен."</string>
@@ -446,10 +445,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Развернуть"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Свернуть"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Блокировка в приложении включена"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопки \"Назад\" и \"Обзор\"."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Приложение останется активным, пока вы не отмените блокировку, нажав и удерживая кнопку \"Обзор\"."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"ОК"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Нет, спасибо"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Скрыть параметр \"<xliff:g id="TILE_LABEL">%1$s</xliff:g>\"?"</string>
@@ -516,28 +513,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Включено"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Отключено"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"С помощью этой функции вы можете устанавливать уровень важности уведомлений от 0 до 5 для каждого приложения.\n\n"<b>"Уровень 5"</b>\n"‒ Помещать уведомления в начало списка.\n‒ Показывать полноэкранные уведомления.\n‒ Показывать всплывающие уведомления.\nУровень 4\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Показывать всплывающие уведомления.\nУровень 3\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\nУровень 2\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\n‒ Не использовать звук и вибрацию.\nУровень 1\n"<b></b>\n"‒ Не показывать полноэкранные уведомления.\n‒ Не показывать всплывающие уведомления.\n‒ Не использовать звук и вибрацию.\n‒ Не показывать на экране блокировки и в строке состояния.\n‒ Помещать уведомления в конец списка.\nУровень 0\n"<b></b>\n"‒ Блокировать все уведомления приложения."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Уведомления"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Вы больше не будете получать эти уведомления."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g>: уведомления"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Низкий приоритет"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Средний приоритет"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Высокий приоритет"</string>
+    <string name="high_importance" msgid="730741630855788381">"Срочно"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без уведомлений"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Без звука"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Звук"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Звук и всплывающее окно"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Другие настройки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Управление уведомлениями (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 4b540b9..7728570 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"අගුළු තිරය."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"සැකසීම්"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"දළ විශ්ලේෂණය."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"කාර්යාල අගුලු තිරය"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"වසන්න"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi අක්‍රියයි."</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index b6b5361..f19b2a1 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Uzamknutá obrazovka"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Nastavenia"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Prehľad"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Uzamknutá obrazovka pracovného profilu"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zavrieť"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Pripojenie Wi-Fi je vypnuté."</string>
@@ -446,10 +445,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Rozbaliť"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Zbaliť"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Obrazovka je pripnutá"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidiel Späť a Prehľad."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Obsah bude pripnutý v zobrazení, dokým ho neuvoľníte. Uvoľníte ho stlačením a podržaním tlačidla Prehľad."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Dobre"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nie, vďaka"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Skryť <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -516,28 +513,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Zapnuté"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Vypnuté"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Pomocou ovládacích prvkov zobrazovania upozornení môžete nastaviť pre upozornenia aplikácie úroveň dôležitosti od 0 do 5. \n\n"<b>"Úroveň 5"</b>" \n– Zobrazovať v hornej časti zoznamu upozornení. \n– Povoliť prerušenia na celú obrazovku. \n– Vždy zobrazovať čiastočne. \n\n"<b>"Úroveň 4"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Vždy zobrazovať čiastočne. \n\n"<b>"Úroveň 3"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n\n"<b>"Úroveň 2"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n– Nikdy nespúšťať zvuk ani vibrácie. \n\n"<b>"Úroveň 1"</b>" \n– Zabrániť prerušeniam na celú obrazovku. \n– Nikdy nezobrazovať čiastočne. \n– Nikdy nespúšťať zvuk ani vibrácie. \n– Skryť na uzamknutej obrazovke a v stavovom riadku. \n– Zobraziť v dolnej časti zoznamu upozornení. \n\n"<b>"Úroveň 0"</b>" \n– Blokovať všetky upozornenia z aplikácie."</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Upozornenia"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Takéto upozornenia už nebudete dostávať."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Upozornenia aplikácie <xliff:g id="APP">%s</xliff:g>"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nízka"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Stredná"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Vysoká"</string>
+    <string name="high_importance" msgid="730741630855788381">"Neodkladná"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bez zvuku a vizuálneho vyrušenia"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Zobraziť bez zvukov"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Vydať zvukový signál"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Vydať zvukový signál a vyskočiť na obrazovku"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Ovládacie prvky pre upozornenia z aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index b9a8266..67eec2f 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Zaklenjen zaslon"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Nastavitve"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Pregled."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Zaklenjen zaslon delovnega profila"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Zapri"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi je izklopljen."</string>
@@ -446,10 +445,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Razširi"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Strni"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Zaslon je pripet"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, hkrati pridržite gumba za nazaj in pregled."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"S tem ostane zaslon viden, dokler ga ne odpnete. Če ga želite odpeti, pridržite gumb za pregled."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Razumem"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ne, hvala"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Želite skriti <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -516,28 +513,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Vklopljeno"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Izklopljeno"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"S kontrolniki za pomebnost obvestila je mogoče za obvestila aplikacije nastaviti stopnjo pomembnosti od 0 do 5. \n\n"<b>"Stopnja 5"</b>" \n– Prikaz na vrhu seznama obvestil \n– Omogočanje prekinitev v celozaslonskem načinu \n– Vedno prikaži hitre predoglede \n\n"<b>"Stopnja 4"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Vedno prikaži hitre predoglede \n\n"<b>"Stopnja 3"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Nikoli ne prikaži hitrih predogledov \n\n"<b>"Stopnja 2"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Nikoli ne prikaži hitrih predogledov \n– Nikoli ne uporabi zvoka in vibriranja \n\n"<b>"Stopnja 1"</b>" \n– Preprečevanje prekinitev v celozaslonskem načinu \n– Nikoli ne prikaži hitrih predogledov \n– Nikoli ne uporabi zvoka in vibriranja \n– Skrivanje na zaklenjenem zaslonu in v vrstici stanja \n– Prikaz na dnu seznama obvestil \n\n"<b>"Stopnja 0"</b>" \n– Blokiranje vseh obvestil aplikacije"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Obvestila"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Teh obvestil ne boste več prejemali."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Obvestila iz aplikacije <xliff:g id="APP">%s</xliff:g> za"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Nizka"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Srednja"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Visoka"</string>
+    <string name="high_importance" msgid="730741630855788381">"Nujno"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Brez zvočne ali vizualne prekinitve"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Prikaži brez zvoka"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Predvajaj zvok"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Predvajaj zvok in prikaži na zaslonu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Več nastavitev"</string>
     <string name="notification_done" msgid="5279426047273930175">"Dokončano"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrolniki obvestil za aplikacijo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index d54b5a3..f4d83c9 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Ekrani i kyçjes."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Cilësimet"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Përmbledhja."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ekrani i kyçjes së punës"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Mbylle"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi është i çaktivizuar."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Zgjeroje"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Mbylle"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekrani u gozhdua"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Prapa\" dhe \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Kjo e ruan në pamje deri sa ta heqësh nga gozhdimi. Prek dhe mbaj të shtypur \"Përmbledhje\" për ta hequr nga gozhdimi."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"E kuptova!"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Jo, faleminderit!"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Të fshihet <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Aktiv"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Joaktiv"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Me kontrollet e njoftimit të energjisë, mund të caktosh një nivel rëndësie nga 0 në 5 për njoftimet e një aplikacioni. \n\n"<b>"Niveli 5"</b>" \n- Shfaq në krye të listës së njoftimeve \n- Lejo ndërprerjen e ekranit të plotë \n- Gjithmonë shfaq shpejt \n\n"<b>"Niveli 4"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Gijthmonë shfaq shpejt \n\n"<b>"Niveli 3"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n\n"<b>"Niveli 2"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n- Asnjëherë mos lësho tingull dhe dridhje \n\n"<b>"Niveli 1"</b>" \n- Parandalo ndërprerjen e ekranit të plotë \n- Asnjëherë mos shfaq shpejt \n- Asnjëherë mos lësho tingull ose dridhje \n- Fshih nga ekrani i kyçjes dhe shiriti i statusit \n- Shfaq në fund të listës së njoftimeve \n\n"<b>"Niveli 0"</b>" \n- Blloko të gjitha njoftimet nga aplikacioni"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Njoftime"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Këto njoftime nuk do t\'i marrësh më."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Njoftimet e <xliff:g id="APP">%s</xliff:g> për"</string>
+    <string name="min_importance" msgid="7559703098688382595">"I ulët"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Mesatar"</string>
+    <string name="default_importance" msgid="6400766013567512061">"I lartë"</string>
+    <string name="high_importance" msgid="730741630855788381">"Urgjent"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Asnjë tingull apo ndërprerje vizuale"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Shfaq në heshtje"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Bëj tingull"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Bëj një tingull dhe shfaq në ekran"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Cilësime të tjera"</string>
     <string name="notification_done" msgid="5279426047273930175">"U krye"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Kontrollet e njoftimeve të <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 727c01e..ffb5312 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -186,8 +186,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Закључани екран."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Подешавања"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Преглед."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Закључани екран за посао"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Затвори"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi је искључен."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Прошири"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Скупи"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екран је закачен"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Назад и Преглед да бисте га откачили."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"На овај начин се ово стално приказује док га не откачите. Додирните и задржите Преглед да бисте га откачили."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Важи"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Не, хвала"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Желите ли да сакријете <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Укључено"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Искључено"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Помоћу напредних контрола за обавештења можете да подесите ниво важности од 0. до 5. за обавештења апликације. \n\n"<b>"5. ниво"</b>" \n– Приказују се у врху листе обавештења \n- Дозволи прекид режима целог екрана \n– Увек завируј \n\n"<b>"4. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Увек завируј \n\n"<b>"3. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n\n"<b>"2. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n– Никада не производи звук или вибрацију \n\n"<b>"1. ниво"</b>" \n– Спречи прекид режима целог екрана \n– Никада не завируј \n– Никада не производи звук или вибрацију \n– Сакриј на закључаном екрану и статусној траци \n– Приказују се у дну листе обавештења \n\n"<b>"0. ниво"</b>" \n– Блокирај сва обавештења из апликације"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Обавештења"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Више нећете да добијате ова обавештења."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Обавештења апликације <xliff:g id="APP">%s</xliff:g> за"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Ниско"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Средње"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Високо"</string>
+    <string name="high_importance" msgid="730741630855788381">"Хитно"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без звучног сигнала или визуелног обавештења"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Приказује се без звучног сигнала"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Емитује се звучни сигнал"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Емитује се звучни сигнал и приказује се на екрану"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Контроле обавештења за апликацију <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index a04a761..153b4c5 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Låsskärm."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Inställningar"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Översikt."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Låsskärm för arbete"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Stäng"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi har inaktiverats."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Utöka"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Komprimera"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skärmen har fästs"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Skärmen visas tills du lossar den. Tryck länge på Tillbaka och Översikt om du vill lossa skärmen."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Skärmen visas tills du lossar den. Tryck länge på Översikt om du vill lossa skärmen."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Nej tack"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Vill du dölja <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Av"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"På"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Med aviseringsinställningarna kan du ange prioritetsnivå från 0 till 5 för aviseringar från en app. \n\n"<b>"Nivå 5"</b>" \n– Visa högst upp i aviseringslistan\n– Tillåt avbrott i helskärmsläge \n– Snabbvisa alltid \n\n"<b>"Nivå 4"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa alltid \n\n"<b>"Nivå 3"</b>" \n- Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n\n"<b>"Nivå 2"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n– Aldrig med ljud eller vibration \n\n"<b>"Nivå 1"</b>" \n– Tillåt inte avbrott i helskärmsläge \n– Snabbvisa aldrig \n– Aldrig med ljud eller vibration \n– Visa inte på låsskärmen och i statusfältet \n– Visa längst ned i aviseringslistan \n\n"<b>"Nivå 0"</b>" \n– Blockera alla aviseringar från appen"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Aviseringar"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Inga fler aviseringar av det här slaget visas."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Aviseringar från <xliff:g id="APP">%s</xliff:g> –"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Låg"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Medelhög"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Hög"</string>
+    <string name="high_importance" msgid="730741630855788381">"Brådskande"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Spela inte upp ljud och visa inte"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Visa utan ljud"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Spela upp ljud"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Spela upp ljud och visa på skärmen"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Klar"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Inställningar för <xliff:g id="APP_NAME">%1$s</xliff:g>-aviseringar"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 49c1860..9793e12 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Skrini iliyofungwa."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Mipangilio"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Muhtasari."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Skrini iliyofungwa ya kazini"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Funga"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wifi imezimwa."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Panua"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Kunja"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Skrini imebandikwa"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Nyuma na Muhtasari ili ubandue."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Hali hii huifanya ionekane hadi utakapoibandua. Gusa na ushikilie kipengele cha Muhtasari ili ubandue."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Nimeelewa"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Hapana, asante"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ungependa kuficha <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Imewashwa"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Imezimwa"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ukiwa na udhibiti wa arifa, unaweza kuweka kiwango cha umuhimu wa arifa za programu kuanzia 0 hadi 5. \n\n"<b>"Kiwango cha 5"</b>" \n- Onyesha katika sehemu ya juu ya orodha ya arifa \n- Ruhusu ukatizaji wa skrini nzima \n- Ruhusu arifa za kuchungulia kila wakati\n\n"<b>"Kiwango cha 4"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Ruhusu arifa za kuchungulia kila wakati \n\n"<b>"Kiwango cha 3"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Usiruhusu kamwe arifa za kuchungulia\n\n"<b>"Kiwango cha 2"</b>" \n- Zuia ukatizaji wa skrini nzima\n- Usiruhusu kamwe arifa za kuchungulia \n- Usiruhusu kamwe sauti au mtetemo \n\n"<b>"Kiwango cha 1"</b>" \n- Zuia ukatizaji wa skrini nzima \n- Usiruhusu kamwe arifa za kuchungulia \n- Usiruhusu kamwe sauti na mtetemo \n- Usionyeshe skrini iliyofungwa na sehemu ya arifa \n- Onyesha katika sehemu ya chini ya orodha ya arifa \n\n"<b>"Kiwango cha 0"</b>" \n- Zuia arifa zote kutoka programu"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Arifa"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Hutapokea arifa hizi tena."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Arifa za <xliff:g id="APP">%s</xliff:g> za"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Chini"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Wastani"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Juu"</string>
+    <string name="high_importance" msgid="730741630855788381">"Dharura"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Hakuna kukatizwa kwa sauti au maonyesho"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Onyesha chinichini"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Toa sauti"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Toa sauti na ibukizi kwenye skrini"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mipangilio zaidi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Nimemaliza"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Vidhibiti vya arifa za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index de395b8..7ef6872 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"பூட்டுத் திரை."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"அமைப்பு"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"மேலோட்டப் பார்வை."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"பணிப் பூட்டுத் திரை"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"மூடு"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"வைஃபை முடக்கப்பட்டது."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"விரிவாக்கு"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"சுருக்கு"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"திரை பொருத்தப்பட்டது"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, முந்தையது மற்றும் மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"பொருத்தியதை அகற்றும் வரை இதைக் காட்சியில் வைக்கும். அகற்ற, மேலோட்டப் பார்வையைத் தொட்டுப் பிடிக்கவும்."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"புரிந்தது"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"வேண்டாம்"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ஐ மறைக்கவா?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"இயக்கத்தில்"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"முடக்கத்தில்"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"ஆற்றல்மிக்க அறிவிப்புக் கட்டுப்பாடுகள் மூலம், பயன்பாட்டின் அறிவிப்புகளுக்கு முக்கியத்துவ நிலையை (0-5) அமைக்கலாம். \n\n"<b>"நிலை 5"</b>" \n- அறிவிப்புப் பட்டியலின் மேலே காட்டும் \n- முழுத் திரைக் குறுக்கீட்டை அனுமதிக்கும் \n- எப்போதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டும் \n\n"<b>"நிலை 4"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- எப்போதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டும் \n\n"<b>"நிலை 3"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n\n"<b>"நிலை 2"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n- ஒருபோதும் ஒலி எழுப்பாது, அதிர்வுறாது \n\n"<b>"நிலை 1"</b>" \n- முழுத் திரைக் குறுக்கீட்டைத் தடுக்கும் \n- ஒருபோதும் நடப்புத் திரையின் மேல் பகுதியில் அறிவிப்புகளைக் காட்டாது \n- ஒருபோதும் ஒலி எழுப்பாது அல்லது அதிர்வுறாது \n- பூட்டுத்திரை மற்றும் நிலைப்பட்டியிலிருந்து மறைக்கும் \n- அறிவிப்புகள் பட்டியலின் கீழே காட்டும் \n\n"<b>"நிலை 0"</b>" \n- பயன்பாட்டின் எல்லா அறிவிப்புகளையும் தடுக்கும்"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"அறிவிப்புகள்"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"இந்த அறிவிப்புகளை இனி பெறமாட்டீர்கள்."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> அறிவிப்புகள்"</string>
+    <string name="min_importance" msgid="7559703098688382595">"குறைவான முக்கியத்துவம்"</string>
+    <string name="low_importance" msgid="6891335321576225228">"நடுத்தர முக்கியத்துவம்"</string>
+    <string name="default_importance" msgid="6400766013567512061">"அதிக முக்கியத்துவம்"</string>
+    <string name="high_importance" msgid="730741630855788381">"அவசரம்"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"ஒலியெழுப்பாது அல்லது காட்சிக் குறுக்கீடு செய்யாது"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"ஒலிக்காமல் காட்டும்"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"ஒலியெழுப்பும்"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"ஒலியெழுப்பி, திரையில் காட்டும்"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"மேலும் அமைப்புகள்"</string>
     <string name="notification_done" msgid="5279426047273930175">"முடிந்தது"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> அறிவிப்புக் கட்டுப்பாடுகள்"</string>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 2254043..f55d95e 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"లాక్ స్క్రీన్."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"సెట్టింగ్‌లు"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"అవలోకనం."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"కార్యాలయ లాక్ స్క్రీన్"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"మూసివేస్తుంది"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"వైఫై ఆఫ్ చేయబడింది."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"విస్తరింపజేయండి"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"కుదించండి"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"స్క్రీన్ పిన్ చేయబడింది"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి వెనుకకు మరియు స్థూలదృష్టి తాకి &amp; అలాగే పట్టుకోండి."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"దీని వలన మీరు అన్‌పిన్ చేసే వరకు ఇది వీక్షణలో ఉంచబడుతుంది. అన్‌పిన్ చేయడానికి స్థూలదృష్టిని తాకి &amp; అలాగే పట్టుకోండి."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"అర్థమైంది"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"వద్దు, ధన్యవాదాలు"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g>ని దాచాలా?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"ఆన్‌లో ఉన్నాయి"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"ఆఫ్‌లో ఉన్నాయి"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"పవర్ నోటిఫికేషన్ నియంత్రణలతో, మీరు అనువర్తన నోటిఫికేషన్‌ల కోసం ప్రాముఖ్యత స్థాయిని 0 నుండి 5 వరకు సెట్ చేయవచ్చు. \n\n"<b>"స్థాయి 5"</b>" \n- నోటిఫికేషన్ జాబితా పైభాగంలో చూపబడతాయి \n- పూర్తి స్క్రీన్ అంతరాయం అనుమతించబడుతుంది \n- ఎల్లప్పుడూ త్వరిత వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 4"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎల్లప్పుడూ త్వరిత వీక్షణ అందించబడుతుంది \n\n"<b>"స్థాయి 3"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n\n"<b>"స్థాయి 2"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం మరియు వైబ్రేషన్ చేయవు \n\n"<b>"స్థాయి 1"</b>" \n- పూర్తి స్క్రీన్ అంతరాయం నిరోధించబడుతుంది \n- ఎప్పుడూ త్వరిత వీక్షణ అందించబడదు \n- ఎప్పుడూ శబ్దం లేదా వైబ్రేట్ చేయవు \n- లాక్ స్క్రీన్ మరియు స్థితి పట్టీ నుండి దాచబడతాయి \n- నోటిఫికేషన్ జాబితా దిగువ భాగంలో చూపబడతాయి \n\n"<b>"స్థాయి 0"</b>" \n- అనువర్తనం నుండి అన్ని నోటిఫికేషన్‌లు బ్లాక్ చేయబడతాయి"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"నోటిఫికేషన్‌లు"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"మీరు ఇకపై ఈ నోటిఫికేషన్‌లను పొందరు."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"దీని కోసం <xliff:g id="APP">%s</xliff:g> నోటిఫికేషన్‌లు"</string>
+    <string name="min_importance" msgid="7559703098688382595">"తక్కువ"</string>
+    <string name="low_importance" msgid="6891335321576225228">"మధ్యస్థం"</string>
+    <string name="default_importance" msgid="6400766013567512061">"అధికం"</string>
+    <string name="high_importance" msgid="730741630855788381">"అత్యవసరం"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"శబ్ద లేదా దృశ్య అంతరాయం కలిగించవద్దు"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"నిశ్శబ్దంగా చూపు"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"శబ్దం చేయి"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"శబ్దం చేసి, స్క్రీన్‌పై చూపు"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"మరిన్ని సెట్టింగ్‌లు"</string>
     <string name="notification_done" msgid="5279426047273930175">"పూర్తయింది"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> నోటిఫికేషన్ నియంత్రణలు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 258ccf6..0e18876 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"ล็อกหน้าจอ"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"การตั้งค่า"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"ภาพรวม"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"หน้าจอล็อกของโปรไฟล์งาน"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"ปิด"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"ปิด Wi-Fi แล้ว"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index c156a8e..0e01e9c 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Lock screen."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Mga Setting"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Overview"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Lock screen sa trabaho"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Isara"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Na-off ang wifi."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index e5dddbe..9987f94 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Kilit ekranı"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Ayarlar"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Genel Bakış."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"İş profili kilit ekranı"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Kapat"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Kablosuz kapatıldı."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Genişlet"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Daralt"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran sabitlendi"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Geri\'ye ve Genel Bakış\'a dokunup basılı tutun."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Bu işlem, siz sabitlemeyi kaldırana kadar ekranı görünür durumda tutar. Sabitlemeyi kaldırmak için Genel bakış\'a dokunup basılı tutun."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Anladım"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Hayır, teşekkürler"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> gizlensin mi?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Açık"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Kapalı"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Güç bildirim kontrolleriyle, bir uygulamanın bildirimleri için 0 ile 5 arasında bir önem düzeyi ayarlayabilirsiniz. \n\n"<b>"5. Düzey"</b>" \n- Bildirim listesinin en üstünde gösterilsin \n- Tam ekran kesintisine izin verilsin \n- Ekranda her zaman kısaca belirsin \n\n"<b>"4. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda her zaman kısaca belirsin \n\n"<b>"3. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman kısaca belirmesin \n\n"<b>"2. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman belirmesin \n- Hiçbir zaman ses çıkarmasın ve titreştirmesin \n\n"<b>"1. Düzey"</b>" \n- Tam ekran kesintisi engellensin \n- Ekranda hiçbir zaman kısaca belirmesin \n- Hiçbir zaman ses çıkarmasın veya titreştirmesin \n- Kilit ekranından ve durum çubuğundan gizlensin \n- Bildirim listesinin en altında gösterilsin \n\n"<b>"0. Düzey"</b>" \n- Uygulamadan gelen tüm bildirimler engellensin"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirimler"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Bu bildirimleri artık almayacaksınız."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Şunun için <xliff:g id="APP">%s</xliff:g> bildirimleri:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Düşük"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Orta"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Yüksek"</string>
+    <string name="high_importance" msgid="730741630855788381">"Acil"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Ses veya görsel kesme yok"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Sessiz bir şekilde göster"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Ses çıkar"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Ses çıkar ve ekranda göster"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirim denetimleri"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 50887c6..57b8d18 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -189,8 +189,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Заблокований екран."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Налаштування"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Огляд."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Екран блокування завдання"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Закрити"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi вимкнено."</string>
@@ -446,10 +445,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Розгорнути"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Згорнути"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Екран закріплено"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопки \"Назад\" та \"Огляд\"."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ви постійно бачитимете екран, доки не відкріпите його. Щоб відкріпити екран, натисніть і втримуйте кнопку \"Огляд\"."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Зрозуміло"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Ні, дякую"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Сховати <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -516,28 +513,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Увімк."</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Вимк."</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"За допомогою елементів керування сповіщеннями ви можете налаштувати пріоритет сповіщень додатка – від 0 до 5 рівня. \n\n"<b>"Рівень 5"</b>\n"- Показувати сповіщення вгорі списку \n- Виводити на весь екран \n- Завжди показувати короткі сповіщення \n\n"<b>"Рівень 4"</b>\n"- Не виводити на весь екран \n- Завжди показувати короткі сповіщення \n\n"<b>"Рівень 3"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n\n"<b>"Рівень 2"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n- Вимкнути звук і вібросигнал \n\n"<b>"Рівень 1"</b>\n"- Не виводити на весь екран \n- Не показувати короткі сповіщення \n- Вимкнути звук і вібросигнал \n- Не показувати на заблокованому екрані та в рядку стану \n- Показувати сповіщення внизу списку \n\n"<b>"Рівень 0"</b>\n"- Блокувати всі сповіщення з додатка"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Сповіщення"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ви більше не отримуватимете ці сповіщення."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Сповіщення з додатка <xliff:g id="APP">%s</xliff:g>:"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Низький"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Середній"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Високий"</string>
+    <string name="high_importance" msgid="730741630855788381">"Терміново"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Без звуку та візуальних сповіщень"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Показувати без звукового сигналу"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Зі звуком"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Зі звуком і спливаючими вікнами"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Більше налаштувань"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Елементи керування сповіщеннями додатка <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index f9ca3b2..50170b8 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"مقفل اسکرین۔"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"ترتیبات"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"مجموعی جائزہ۔"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"دفتری مقفل اسکرین"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"بند کریں"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>۔"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"‏Wifi کو آف کر دیا گیا۔"</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"پھیلائیں"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"سکیڑیں"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"اسکرین پن کردہ ہے"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے پیچھے اور مجموعی جائزہ بٹنز کو ٹچ کریں اور دبائے رکھیں۔"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"یہ اسے اس وقت تک نظر میں رکھتا ہے جب تک آپ اس سے پن ہٹا نہیں دیتے۔ پن ہٹانے کیلئے مجموعی جائزہ بٹن کو ٹچ کریں اور دبائے رکھیں۔"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"سمجھ آ گئی"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"نہیں شکریہ"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> کو چھپائیں؟"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"آن"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"آف"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"پاور اطلاع کنٹرولز کے ساتھ آپ کسی ایپ کی اطلاعات کیلئے 0 سے 5 تک اہمیت کی سطح سیٹ کر سکتے ہیں۔ \n\n"<b>"سطح 5"</b>\n"- اطلاعات کی فہرست کے اوپر دکھائیں \n- پوری اسکرین کی مداخلت کی اجازت دیں \n- ہمیشہ جھانکنا\n\n"<b>"سطح 4"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- ہمیشہ جھانکنا\n\n"<b>"سطح 3"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- کبھی نہ جھانکنا \n\n"<b>"سطح 2"</b>\n"- پوری اسکرین کی مداخلت کو روکیں \n- کبھی نہ جھانکنا \n- کبھی آواز اور ارتعاش پیدا نہ کرنا \n\n"<b>" سطح 1"</b>\n"- پوری اسکرین کی مداخلت کو روکنا \n- کبھی نہ جھانکنا \n- کبھی بھی آواز یا ارتعاش پیدا نہ کرنا\n- مقفل اسکرین اور اسٹیٹس بار سے چھپانا \n - اطلاع کی فہرست کی نیچے دکھانا \n\n"<b>"سطح 0"</b>\n"- ایپ سے تمام اطلاعات مسدود کریں"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"اطلاعات"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"آپ کو یہ اطلاعات مزید نہیں ملیں گی۔"</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> کیلئے اطلاعات"</string>
+    <string name="min_importance" msgid="7559703098688382595">"کم"</string>
+    <string name="low_importance" msgid="6891335321576225228">"متوسط"</string>
+    <string name="default_importance" msgid="6400766013567512061">"زیادہ"</string>
+    <string name="high_importance" msgid="730741630855788381">"ارجنٹ"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"آواز یا بصری مداخلت نہیں ہے"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"خاموشی سے دکھائیں"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"آواز نکالیں"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"آواز نکالیں اور اسکرین پر پاپ کریں"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
     <string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے نوٹیفکیشن کنٹرولز"</string>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 413cd7a3..fba46753 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Qulflash ekrani."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Sozlamalar"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Umumiy nazar."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ishchi ekran qulfi"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Yopish"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Wi-Fi o‘chirildi."</string>
@@ -442,10 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Yoyish"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Yig‘ish"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Ekran qadaldi"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Orqaga” va “Umumiy ma’lumot” tugmalarini bosib turing."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Ekran yechilmaguncha u o‘zgarmas holatda qoladi. Uni yechish uchun “Umumiy ma’lumot” tugmasini bosib turing."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"OK"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Yo‘q, kerakmas"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"<xliff:g id="TILE_LABEL">%1$s</xliff:g> berkitilsinmi?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Yoniq"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"O‘chiq"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Bildirishnomalar uchun kengaytirilgan boshqaruv yordamida ilova bildirishnomalarining muhimlik darajasini (0-5) sozlash mumkin. \n\n"<b>"5-daraja"</b>" \n- Bildirishnomani ro‘yxatning boshida ko‘rsatish \n- To‘liq ekranli bildirishnomalarni ko‘rsatish \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatish \n\n"<b>"4-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatish \n\n"<b>"3-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n\n"<b>"2-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n- Ovoz va tebranishdan foydalanmaslik \n\n"<b>"1-daraja"</b>" \n- To‘liq ekranli bildirishnomalarni ko‘rsatmaslik \n- Qalqib chiquvchi bildirishnomalarni ko‘rsatmaslik \n- Ovoz va tebranishdan foydalanmaslik \n- Ekran qulfi va holat qatorida ko‘rsatmaslik \n- Bildirishnomani ro‘yxatning oxirida ko‘rsatish \n\n"<b>"0-daraja"</b>" \n- Ilovadan keladigan barcha bildirishnomalarni bloklash"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Bildirishnomalar"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ushbu bildirishnomalar endi ko‘rsatilmaydi."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> bildirishnomalari"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Muhim emas"</string>
+    <string name="low_importance" msgid="6891335321576225228">"O‘rtacha"</string>
+    <string name="default_importance" msgid="6400766013567512061">"O‘ta muhim"</string>
+    <string name="high_importance" msgid="730741630855788381">"Shoshilinch"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Bildirishnomalarsiz"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Ovozsiz"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Ovozli"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Ovoz va qalqib chiquvchi oyna"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnomalarini boshqarish"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index dde279b..1363d8a 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Màn hình khóa."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Cài đặt"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Tổng quan."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Màn hình khóa công việc"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Đóng"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"Đã tắt Wifi."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Mở rộng"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Thu gọn"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Màn hình được ghim"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Quay lại và Tổng quan để bỏ ghim."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Thao tác này sẽ duy trì hiển thị màn hình cho đến khi bạn bỏ ghim. Hãy chạm và giữ Tổng quan để bỏ ghim."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ok"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Không, cảm ơn"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Ẩn <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -512,28 +509,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Bật"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Tắt"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Với các kiểm soát thông báo nguồn, bạn có thể đặt cấp độ quan trọng từ 0 đến 5 cho các thông báo của ứng dụng. \n\n"<b>"Cấp 5"</b>" \n- Hiển thị ở đầu danh sách thông báo \n- Cho phép gián đoạn ở chế độ toàn màn hình \n- Luôn xem nhanh \n\n"<b>"Cấp 4"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Luôn xem nhanh \n\n"<b>"Cấp 3"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n\n"<b>"Cấp 2"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n- Không bao giờ có âm báo và rung \n\n"<b>"Cấp 1"</b>" \n- Ngăn gián đoạn ở chế độ toàn màn hình \n- Không bao giờ xem nhanh \n- Không bao giờ có âm báo và rung \n- Ẩn khỏi màn hình khóa và thanh trạng thái \n- Hiển thị ở cuối danh sách thông báo \n\n"<b>"Cấp 0"</b>" \n- Chặn tất cả các thông báo từ ứng dụng"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Thông báo"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Bạn sẽ không nhận được những thông báo này nữa."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"Thông báo của <xliff:g id="APP">%s</xliff:g> cho"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Thấp"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Trung bình"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Cao"</string>
+    <string name="high_importance" msgid="730741630855788381">"Khẩn cấp"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Không làm gián đoạn bằng âm báo hoặc hình ảnh"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Hiển thị mà không phát âm báo"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Phát âm báo"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Phát âm báo và hiển thị trên màn hình"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Cài đặt khác"</string>
     <string name="notification_done" msgid="5279426047273930175">"Xong"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"Điều khiển thông báo <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 4f5518b..91a4734 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"锁定屏幕。"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"设置"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"概览。"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"工作锁定屏幕"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"关闭"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WLAN已关闭。"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 947848e..0b62aea 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -187,8 +187,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"上鎖畫面。"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"設定"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"概覽"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"工作螢幕鎖定"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"關閉"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WiFi 已關閉。"</string>
@@ -442,8 +441,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"展開"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"收合"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"螢幕已固定"</string>
-    <string name="screen_pinning_description" msgid="8909878447196419623">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [返回] 按鈕和 [總覽] 按鈕即可取消固定。"</string>
-    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"這會讓目前的螢幕畫面保持顯示狀態,直到取消固定為止。按住 [總覽] 按鈕即可取消固定。"</string>
+    <string name="screen_pinning_description" msgid="8909878447196419623">"畫面將會繼續顯示,直至您取消固定。按住 [返回] 和 [概覽] 即可取消固定。"</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"畫面將會繼續顯示,直至您取消固定。按住 [概覽] 即可取消固定。"</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"知道了"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"不用了,謝謝"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"隱藏 <xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -511,7 +510,7 @@
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"關閉"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"通知控制項讓您設定應用程式通知的重要性 (0 至 5 級)。\n\n"<b>"第 5 級"</b>" \n- 在通知清單頂部顯示 \n- 允許全螢幕騷擾 \n- 一律顯示通知 \n\n"<b>"第 4 級"</b>" \n- 阻止全螢幕騷擾 \n- 一律顯示通知 \n\n"<b>"第 3 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n\n"<b>"第 2 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n- 永不發出聲響和震動 \n\n"<b>"第 1 級"</b>" \n- 阻止全螢幕騷擾 \n- 永不顯示通知 \n- 永不發出聲響和震動 \n- 從上鎖畫面和狀態列中隱藏 \n- 在通知清單底部顯示 \n\n"<b>"第 0 級"</b>" \n- 封鎖所有應用程式通知"</string>
     <string name="notification_header_default_channel" msgid="7506845022070889909">"通知"</string>
-    <string name="notification_channel_disabled" msgid="5805874247999578073">"你不會再收到這類通知。"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"您不會再收到這些通知。"</string>
     <string name="notification_importance_header_app" msgid="3572576545406258751">"以下頻道的「<xliff:g id="APP">%s</xliff:g>」通知:"</string>
     <string name="min_importance" msgid="7559703098688382595">"低"</string>
     <string name="low_importance" msgid="6891335321576225228">"中"</string>
@@ -520,7 +519,7 @@
     <string name="notification_importance_min" msgid="3237794091374404537">"不發出音效或顯示通知"</string>
     <string name="notification_importance_low" msgid="8929105501798019743">"顯示通知但不發出音效"</string>
     <string name="notification_importance_default" msgid="9025125660733917469">"發出音效"</string>
-    <string name="notification_importance_high" msgid="3316555356062640222">"發出音效並在畫面上彈出通知"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"發出音效並在螢幕上彈出通知"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
     <string name="notification_done" msgid="5279426047273930175">"完成"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」通知控制項"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index b0aa942..905506e 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"螢幕鎖定。"</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"設定"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"總覽。"</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Work 螢幕鎖定"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"關閉"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"WiFi 已關閉。"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index d5f98c2..6592bd0 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -185,8 +185,7 @@
     <string name="accessibility_desc_lock_screen" msgid="5625143713611759164">"Khiya isikrini."</string>
     <string name="accessibility_desc_settings" msgid="3417884241751434521">"Izilungiselelo"</string>
     <string name="accessibility_desc_recent_apps" msgid="4876900986661819788">"Buka konke."</string>
-    <!-- no translation found for accessibility_desc_work_lock (4288774420752813383) -->
-    <skip />
+    <string name="accessibility_desc_work_lock" msgid="4288774420752813383">"Ukukhiya isikrini somsebenzi"</string>
     <string name="accessibility_desc_close" msgid="7479755364962766729">"Vala"</string>
     <string name="accessibility_quick_settings_wifi" msgid="5518210213118181692">"<xliff:g id="SIGNAL">%1$s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi_changed_off" msgid="8716484460897819400">"I-Wifi ivaliwe."</string>
@@ -440,10 +439,8 @@
     <string name="accessibility_volume_expand" msgid="5946812790999244205">"Nweba"</string>
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"Goqa"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"Isikrini siphiniwe"</string>
-    <!-- no translation found for screen_pinning_description (8909878447196419623) -->
-    <skip />
-    <!-- no translation found for screen_pinning_description_accessible (426190689254018656) -->
-    <skip />
+    <string name="screen_pinning_description" msgid="8909878447196419623">"Lokhu kuyigcina ibukeka uze ususe ukuphina. Thinta uphinde ubambe okuthi Emuva Nokubuka konke ukuze ususe ukuphina."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"Lokhu kuyigcina ibukeka uze ususe ukuphina. Thinta uphinde ubambe Ukubuka konke ukuze ususe ukuphina."</string>
     <string name="screen_pinning_positive" msgid="3783985798366751226">"Ngiyitholile"</string>
     <string name="screen_pinning_negative" msgid="3741602308343880268">"Cha ngiyabonga"</string>
     <string name="quick_settings_reset_confirmation_title" msgid="748792586749897883">"Fihla i-<xliff:g id="TILE_LABEL">%1$s</xliff:g>?"</string>
@@ -510,28 +507,17 @@
     <string name="tuner_full_importance_settings_on" msgid="7545060756610299966">"Vuliwe"</string>
     <string name="tuner_full_importance_settings_off" msgid="8208165412614935229">"Valiwe"</string>
     <string name="power_notification_controls_description" msgid="4372459941671353358">"Ngezilawuli zesaziso zamandla, ungasetha ileveli ebalulekile kusuka ku-0 kuya ku-5 kusuka kuzaziso zohlelo lokusebenza. \n\n"<b>"Ileveli 5"</b>" \n- Ibonisa phezulu kuhlu lwesaziso \n- Vumela ukuphazamiseka kwesikrini esigcwele \n- Ukuhlola njalo \n\n"<b>"Ileveli 4"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukuhlola njalo \n\n"<b>"Ileveli 3"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n\n"<b>"Ileveli 2"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n- Ungenzi umsindo nokudlidliza \n\n"<b>"Ileveli 1"</b>" \n- Gwema ukuphazamiseka kwesikrini esigcwele \n- Ukungahloli \n- Ungenzi umsindo noma ukudlidliza \n- Fihla kusuka kusikrini sokukhiya nebha yesimo \n- Bonisa phansi kohlu lwesaziso \n\n"<b>"Ileveli 0"</b>" \n- Vimbela zonke izaziso kusuka kuhlelo lokusebenza"</string>
-    <!-- no translation found for notification_header_default_channel (7506845022070889909) -->
-    <skip />
-    <!-- no translation found for notification_channel_disabled (5805874247999578073) -->
-    <skip />
-    <!-- no translation found for notification_importance_header_app (3572576545406258751) -->
-    <skip />
-    <!-- no translation found for min_importance (7559703098688382595) -->
-    <skip />
-    <!-- no translation found for low_importance (6891335321576225228) -->
-    <skip />
-    <!-- no translation found for default_importance (6400766013567512061) -->
-    <skip />
-    <!-- no translation found for high_importance (730741630855788381) -->
-    <skip />
-    <!-- no translation found for notification_importance_min (3237794091374404537) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (8929105501798019743) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (9025125660733917469) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (3316555356062640222) -->
-    <skip />
+    <string name="notification_header_default_channel" msgid="7506845022070889909">"Izaziso"</string>
+    <string name="notification_channel_disabled" msgid="5805874247999578073">"Ngeke usathola lezi zaziso."</string>
+    <string name="notification_importance_header_app" msgid="3572576545406258751">"<xliff:g id="APP">%s</xliff:g> izaziso ze-"</string>
+    <string name="min_importance" msgid="7559703098688382595">"Phansi"</string>
+    <string name="low_importance" msgid="6891335321576225228">"Okulingene"</string>
+    <string name="default_importance" msgid="6400766013567512061">"Okuphezulu"</string>
+    <string name="high_importance" msgid="730741630855788381">"Okuphuthumayo"</string>
+    <string name="notification_importance_min" msgid="3237794091374404537">"Awukho umsindo noma ukuphazamiseka okubukwayo"</string>
+    <string name="notification_importance_low" msgid="8929105501798019743">"Bonisa ngokuthulile"</string>
+    <string name="notification_importance_default" msgid="9025125660733917469">"Yenza umsindo"</string>
+    <string name="notification_importance_high" msgid="3316555356062640222">"Yenza umsindo ne-pop kusikrini"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Izilungiselelo eziningi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Kwenziwe"</string>
     <string name="notification_gear_accessibility" msgid="94429150213089611">"<xliff:g id="APP_NAME">%1$s</xliff:g> izilawuli zasaziso"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 78d211f..6ffdbcb 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -75,6 +75,9 @@
     <!-- Height of a large notification in the status bar -->
     <dimen name="notification_max_height">284dp</dimen>
 
+    <!-- Height of an ambient notification on ambient display -->
+    <dimen name="notification_ambient_height">400dp</dimen>
+
     <!-- Height of a heads up notification in the status bar for legacy custom views -->
     <dimen name="notification_max_heads_up_height_legacy">128dp</dimen>
 
diff --git a/packages/SystemUI/res/values/dimens_grid.xml b/packages/SystemUI/res/values/dimens_grid.xml
index 94ffdb1..0b9836ff 100644
--- a/packages/SystemUI/res/values/dimens_grid.xml
+++ b/packages/SystemUI/res/values/dimens_grid.xml
@@ -21,5 +21,6 @@
   <dimen name="recents_grid_padding_task_view">20dp</dimen>
   <dimen name="recents_grid_task_view_header_height">44dp</dimen>
   <dimen name="recents_grid_task_view_header_button_padding">8dp</dimen>
+  <dimen name="recents_grid_task_view_focused_frame_thickness">8dp</dimen>
 </resources>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 69515fa..a17430a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -760,6 +760,12 @@
     <string name="quick_settings_work_mode_label">Work mode</string>
     <!-- QuickSettings: Label for the toggle to activate Night display (renamed "Night Light" with title caps). [CHAR LIMIT=20] -->
     <string name="quick_settings_night_display_label">Night Light</string>
+    <!-- QuickSettings: NFC tile [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_nfc_label">NFC</string>
+    <!-- QuickSettings: NFC (off) [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_nfc_off">NFC is disabled</string>
+    <!-- QuickSettings: NFC (on) [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_nfc_on">NFC is enabled</string>
 
     <!-- Recents: The empty recents string. [CHAR LIMIT=NONE] -->
     <string name="recents_empty_message">No recent items</string>
diff --git a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
index d98bb23..8141b28 100644
--- a/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/ExpandHelper.java
@@ -326,7 +326,7 @@
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
                 if (DEBUG) Log.d(TAG, "up/cancel");
-                finishExpanding(ev.getActionMasked() == MotionEvent.ACTION_CANCEL,
+                finishExpanding(ev.getActionMasked() == MotionEvent.ACTION_CANCEL /* forceAbort */,
                         getCurrentVelocity());
                 clearView();
                 break;
@@ -587,6 +587,9 @@
             mFlingAnimationUtils.apply(mScaleAnimation, currentHeight, targetHeight, velocity);
             mScaleAnimation.start();
         } else {
+            if (targetHeight != currentHeight) {
+                mScaler.setHeight(targetHeight);
+            }
             mCallback.setUserExpandedChild(mResizedView, nowExpanded);
             mCallback.setUserLockedChild(mResizedView, false);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java b/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java
new file mode 100644
index 0000000..c4470cd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/SysUiServiceProvider.java
@@ -0,0 +1,23 @@
+/*
+ * 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;
+
+/**
+ * The interface for getting core components of SysUI. Exists for Testability
+ * since tests don't have SystemUIApplication as their ApplicationContext.
+ */
+public interface SysUiServiceProvider {
+    <T> T getComponent(Class<T> interfaceType);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUI.java b/packages/SystemUI/src/com/android/systemui/SystemUI.java
index f30baee..6b30a89 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUI.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUI.java
@@ -25,7 +25,7 @@
 import java.io.PrintWriter;
 import java.util.Map;
 
-public abstract class SystemUI {
+public abstract class SystemUI implements SysUiServiceProvider {
     public Context mContext;
     public Map<Class<?>, Object> mComponents;
 
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 1988023..bd4e3dc 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -55,7 +55,7 @@
 /**
  * Application class for SystemUI.
  */
-public class SystemUIApplication extends Application {
+public class SystemUIApplication extends Application implements SysUiServiceProvider {
 
     private static final String TAG = "SystemUIService";
     private static final boolean DEBUG = false;
@@ -239,4 +239,8 @@
     public SystemUI[] getServices() {
         return mServices;
     }
+
+    public static <T> T getComponent(Context context, Class<T> interfaceType) {
+        return ((SysUiServiceProvider) context.getApplicationContext()).getComponent(interfaceType);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index e081b53..00d2298 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -37,7 +37,7 @@
 
     interface Callback {
         default void onNewNotifications() {}
-        default void onBuzzBeepBlinked() {}
+        default void onNotificationHeadsUp() {}
         default void onNotificationLight(boolean on) {}
         default void onPowerSaveChanged(boolean active) {}
     }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 84b22ea..db5a392 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -309,7 +309,7 @@
 
     private DozeHost.Callback mHostCallback = new DozeHost.Callback() {
         @Override
-        public void onBuzzBeepBlinked() {
+        public void onNotificationHeadsUp() {
             onNotification();
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
index 6d0e77c..57857cc 100644
--- a/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
+++ b/packages/SystemUI/src/com/android/systemui/fragments/FragmentHostManager.java
@@ -52,7 +52,7 @@
     private FragmentLifecycleCallbacks mLifecycleCallbacks;
 
     FragmentHostManager(Context context, FragmentService manager, View rootView) {
-        mContext = PluginManager.getInstance(context).getAllPluginContext(context);
+        mContext = context;
         mManager = manager;
         mRootView = rootView;
         mConfigChanges.applyNewConfig(context.getResources());
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
new file mode 100644
index 0000000..967c922
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NfcTile.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2016, The Android Open Source Project
+ * Contributed by the Paranoid Android 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.tiles;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.graphics.drawable.Drawable;
+import android.nfc.NfcAdapter;
+import android.provider.Settings;
+import android.widget.Switch;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+
+/** Quick settings tile: Enable/Disable NFC **/
+public class NfcTile extends QSTile<QSTile.BooleanState> {
+
+    private NfcAdapter mAdapter;
+
+    private boolean mListening;
+
+    public NfcTile(Host host) {
+        super(host);
+    }
+
+    @Override
+    public BooleanState newTileState() {
+        return new BooleanState();
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        mListening = listening;
+        if (mListening) {
+            mContext.registerReceiver(mNfcReceiver,
+                    new IntentFilter(NfcAdapter.ACTION_ADAPTER_STATE_CHANGED));
+            if (mAdapter == null) {
+                try {
+                    mAdapter = NfcAdapter.getNfcAdapter(mContext);
+                } catch (UnsupportedOperationException e) {
+                    mAdapter = null;
+                }
+            }
+        } else {
+            mContext.unregisterReceiver(mNfcReceiver);
+        }
+    }
+
+    @Override
+    public boolean isAvailable() {
+        return mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC);
+    }
+
+    @Override
+    protected void handleUserSwitch(int newUserId) {
+    }
+
+    @Override
+    public Intent getLongClickIntent() {
+        return new Intent(Settings.ACTION_NFC_SETTINGS);
+    }
+
+    @Override
+    protected void handleClick() {
+        if (mAdapter == null) return;
+        MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
+        if (!mAdapter.isEnabled()) {
+            mAdapter.enable();
+        } else {
+            mAdapter.disable();
+        }
+    }
+
+    @Override
+    protected void handleSecondaryClick() {
+        handleClick();
+    }
+
+    @Override
+    public CharSequence getTileLabel() {
+        return mContext.getString(R.string.quick_settings_nfc_label);
+    }
+
+    @Override
+    protected void handleUpdateState(BooleanState state, Object arg) {
+        final Drawable mEnable = mContext.getDrawable(R.drawable.ic_qs_nfc_enabled);
+        final Drawable mDisable = mContext.getDrawable(R.drawable.ic_qs_nfc_disabled);
+        state.value = mAdapter == null ? false : mAdapter.isEnabled();
+        state.label = mContext.getString(R.string.quick_settings_nfc_label);
+        state.icon = new DrawableIcon(state.value ? mEnable : mDisable);
+        state.minimalAccessibilityClassName = state.expandedAccessibilityClassName
+                = Switch.class.getName();
+        state.contentDescription = state.label;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsEvent.QS_NFC;
+    }
+
+    @Override
+    protected String composeChangeAnnouncement() {
+        if (mState.value) {
+            return mContext.getString(R.string.quick_settings_nfc_on);
+        } else {
+            return mContext.getString(R.string.quick_settings_nfc_off);
+        }
+    }
+
+    private BroadcastReceiver mNfcReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            refreshState();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
index 914035b..a7f6b70 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -50,7 +50,7 @@
     /**
      * Returns the task to focus given the current launch state.
      */
-    public int getInitialFocusTaskIndex(int numTasks) {
+    public int getInitialFocusTaskIndex(int numTasks, boolean useGridLayout) {
         RecentsDebugFlags debugFlags = Recents.getDebugFlags();
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
         if (launchedFromApp) {
@@ -66,6 +66,11 @@
                 return numTasks - 1;
             }
 
+            if (useGridLayout) {
+                // If coming from another app to the grid layout, focus the front most task
+                return numTasks - 1;
+            }
+
             // If coming from another app, focus the next task
             return Math.max(0, numTasks - 2);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 7547bc3..cf6357b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -23,6 +23,7 @@
 import static android.view.View.MeasureSpec;
 
 import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityOptions;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
@@ -60,6 +61,7 @@
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
+import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.ForegroundThread;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -131,6 +133,11 @@
                 loader.loadTasks(mContext, plan, launchOpts);
             }
         }
+
+        @Override
+        public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
+            EventBus.getDefault().send(new TaskSnapshotChangedEvent(taskId, snapshot));
+        }
     }
 
     protected static RecentsTaskLoadPlan sInstanceLoadPlan;
@@ -204,8 +211,6 @@
         Resources res = mContext.getResources();
         reloadResources();
         mDummyStackView.reloadOnConfigurationChange();
-        mDummyStackView.getStackAlgorithm().getGridState().setHasDockedTasks(
-            Recents.getSystemServices().hasDockedTask());
     }
 
     /**
@@ -740,8 +745,12 @@
             Task toTask = new Task();
             TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask,
                     windowOverrideRect);
-            Bitmap thumbnail = drawThumbnailTransitionBitmap(toTask, toTransform,
-                    mThumbTransitionBitmapCache);
+            // When using a grid layout, the header is already visible on screen at the target
+            // location, making it unnecessary to draw it in the transition thumbnail.
+            Bitmap thumbnail = stackView.useGridLayout()
+                    ? mThumbTransitionBitmapCache.createAshmemBitmap()
+                    : drawThumbnailTransitionBitmap(toTask, toTransform,
+                            mThumbTransitionBitmapCache);
             if (thumbnail != null) {
                 RectF toTaskRect = toTransform.rect;
                 return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
@@ -772,7 +781,6 @@
         // Get the transform for the running task
         stackView.updateLayoutAlgorithm(true /* boundScroll */);
         stackView.updateToInitialState();
-        boolean isInSplitScreen = Recents.getSystemServices().hasDockedTask();
         stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
                 stackView.getScroller().getStackScroll(), mTmpTransform, null, windowOverrideRect);
         return mTmpTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
new file mode 100644
index 0000000..07c3b3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/TaskSnapshotChangedEvent.java
@@ -0,0 +1,35 @@
+/*
+ * 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.recents.events.ui;
+
+import android.app.ActivityManager.TaskSnapshot;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Sent when a task snapshot has changed.
+ */
+public class TaskSnapshotChangedEvent extends EventBus.Event {
+
+    public final int taskId;
+    public final TaskSnapshot taskSnapshot;
+
+    public TaskSnapshotChangedEvent(int taskId, TaskSnapshot taskSnapshot) {
+        this.taskId = taskId;
+        this.taskSnapshot = taskSnapshot;
+    }
+}
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 3587b89..a2b86d1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -24,7 +24,9 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 
+import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
 import android.app.IActivityManager;
@@ -148,6 +150,7 @@
      */
     public abstract static class TaskStackListener {
         public void onTaskStackChanged() { }
+        public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
         public void onActivityPinned() { }
         public void onPinnedActivityRestartAttempt() { }
         public void onPinnedStackAnimationEnded() { }
@@ -202,6 +205,12 @@
         public void onTaskProfileLocked(int taskId, int userId) {
             mHandler.obtainMessage(H.ON_TASK_PROFILE_LOCKED, taskId, userId).sendToTarget();
         }
+
+        @Override
+        public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot)
+                throws RemoteException {
+            mHandler.obtainMessage(H.ON_TASK_SNAPSHOT_CHANGED, taskId, 0, snapshot).sendToTarget();
+        }
     };
 
     /**
@@ -591,17 +600,17 @@
     /** Returns the top task thumbnail for the given task id */
     public ThumbnailData getTaskThumbnail(int taskId) {
         if (mAm == null) return null;
-        ThumbnailData thumbnailData = new ThumbnailData();
 
         // If we are mocking, then just return a dummy thumbnail
         if (RecentsDebugFlags.Static.EnableMockTasks) {
+            ThumbnailData thumbnailData = new ThumbnailData();
             thumbnailData.thumbnail = Bitmap.createBitmap(mDummyThumbnailWidth,
                     mDummyThumbnailHeight, Bitmap.Config.ARGB_8888);
             thumbnailData.thumbnail.eraseColor(0xff333333);
             return thumbnailData;
         }
 
-        getThumbnail(taskId, thumbnailData);
+        ThumbnailData thumbnailData = getThumbnail(taskId);
         if (thumbnailData.thumbnail != null && !ActivityManager.ENABLE_TASK_SNAPSHOTS) {
             thumbnailData.thumbnail.setHasAlpha(false);
             // We use a dumb heuristic for now, if the thumbnail is purely transparent in the top
@@ -621,11 +630,12 @@
     /**
      * Returns a task thumbnail from the activity manager
      */
-    public void getThumbnail(int taskId, ThumbnailData thumbnailDataOut) {
+    public @NonNull ThumbnailData getThumbnail(int taskId) {
         if (mAm == null) {
-            return;
+            return new ThumbnailData();
         }
 
+        final ThumbnailData thumbnailData;
         if (ActivityManager.ENABLE_TASK_SNAPSHOTS) {
             ActivityManager.TaskSnapshot snapshot = null;
             try {
@@ -634,16 +644,14 @@
                 Log.w(TAG, "Failed to retrieve snapshot", e);
             }
             if (snapshot != null) {
-                thumbnailDataOut.thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot());
-                thumbnailDataOut.orientation = snapshot.getOrientation();
-                thumbnailDataOut.insets.set(snapshot.getContentInsets());
+                thumbnailData = ThumbnailData.createFromTaskSnapshot(snapshot);
             } else {
-                thumbnailDataOut.thumbnail = null;
+                return new ThumbnailData();
             }
         } else {
             ActivityManager.TaskThumbnail taskThumbnail = mAm.getTaskThumbnail(taskId);
             if (taskThumbnail == null) {
-                return;
+                return new ThumbnailData();
             }
 
             Bitmap thumbnail = taskThumbnail.mainThumbnail;
@@ -658,10 +666,12 @@
                 } catch (IOException e) {
                 }
             }
-            thumbnailDataOut.thumbnail = thumbnail;
-            thumbnailDataOut.orientation = taskThumbnail.thumbnailInfo.screenOrientation;
-            thumbnailDataOut.insets.setEmpty();
+            thumbnailData = new ThumbnailData();
+            thumbnailData.thumbnail = thumbnail;
+            thumbnailData.orientation = taskThumbnail.thumbnailInfo.screenOrientation;
+            thumbnailData.insets.setEmpty();
         }
+        return thumbnailData;
     }
 
     /**
@@ -1172,12 +1182,13 @@
 
     private final class H extends Handler {
         private static final int ON_TASK_STACK_CHANGED = 1;
-        private static final int ON_ACTIVITY_PINNED = 2;
-        private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 3;
-        private static final int ON_PINNED_STACK_ANIMATION_ENDED = 4;
-        private static final int ON_ACTIVITY_FORCED_RESIZABLE = 5;
-        private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 6;
-        private static final int ON_TASK_PROFILE_LOCKED = 7;
+        private static final int ON_TASK_SNAPSHOT_CHANGED = 2;
+        private static final int ON_ACTIVITY_PINNED = 3;
+        private static final int ON_PINNED_ACTIVITY_RESTART_ATTEMPT = 4;
+        private static final int ON_PINNED_STACK_ANIMATION_ENDED = 5;
+        private static final int ON_ACTIVITY_FORCED_RESIZABLE = 6;
+        private static final int ON_ACTIVITY_DISMISSING_DOCKED_STACK = 7;
+        private static final int ON_TASK_PROFILE_LOCKED = 8;
 
         @Override
         public void handleMessage(Message msg) {
@@ -1188,6 +1199,13 @@
                     }
                     break;
                 }
+                case ON_TASK_SNAPSHOT_CHANGED: {
+                    for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
+                        mTaskStackListeners.get(i).onTaskSnapshotChanged(msg.arg1,
+                                (TaskSnapshot) msg.obj);
+                    }
+                    break;
+                }
                 case ON_ACTIVITY_PINNED: {
                     for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
                         mTaskStackListeners.get(i).onActivityPinned();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 178cb9f..9b25ef8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -247,6 +247,9 @@
      */
     public static class DockState implements DropTarget {
 
+        public static final int DOCK_AREA_BG_COLOR = 0xFFffffff;
+        public static final int DOCK_AREA_GRID_BG_COLOR = 0xFF000000;
+
         // The rotation to apply to the hint text
         @Retention(RetentionPolicy.SOURCE)
         @IntDef({HORIZONTAL, VERTICAL})
@@ -319,7 +322,8 @@
             private ViewState(int areaAlpha, int hintAlpha, @TextOrientation int hintOrientation,
                     int hintTextResId) {
                 dockAreaAlpha = areaAlpha;
-                dockAreaOverlay = new ColorDrawable(0xFFffffff);
+                dockAreaOverlay = new ColorDrawable(Recents.getConfiguration().isGridEnabled
+                        ? DOCK_AREA_GRID_BG_COLOR : DOCK_AREA_BG_COLOR);
                 dockAreaOverlay.setAlpha(0);
                 hintTextAlpha = hintAlpha;
                 hintTextOrientation = hintOrientation;
@@ -435,7 +439,7 @@
          * @param createMode used to pass to ActivityManager to dock the task
          * @param touchArea the area in which touch will initiate this dock state
          * @param dockArea the visible dock area
-         * @param expandedTouchDockArea the areain which touch will continue to dock after entering
+         * @param expandedTouchDockArea the area in which touch will continue to dock after entering
          *                              the initial touch area.  This is also the new dock area to
          *                              draw.
          */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
index 18735ac..09a3712 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/ThumbnailData.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.recents.model;
 
+import android.app.ActivityManager.TaskSnapshot;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 
@@ -23,7 +24,17 @@
  * Data for a single thumbnail.
  */
 public class ThumbnailData {
+
+    // TODO: Make these final once the non-snapshot path is removed.
     public Bitmap thumbnail;
     public int orientation;
     public final Rect insets = new Rect();
+
+    public static ThumbnailData createFromTaskSnapshot(TaskSnapshot snapshot) {
+        ThumbnailData out = new ThumbnailData();
+        out.thumbnail = Bitmap.createHardwareBitmap(snapshot.getSnapshot());
+        out.insets.set(snapshot.getContentInsets());
+        out.orientation = snapshot.getOrientation();
+        return out;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index ed86d4c..a2ee4c5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -105,6 +105,7 @@
     private static final Interpolator ENTER_WHILE_DOCKING_INTERPOLATOR =
             Interpolators.LINEAR_OUT_SLOW_IN;
 
+    private final int mEnterAndExitFromHomeTranslationOffset;
     private TaskStackView mStackView;
 
     private TaskViewTransform mTmpTransform = new TaskViewTransform();
@@ -113,6 +114,8 @@
 
     public TaskStackAnimationHelper(Context context, TaskStackView stackView) {
         mStackView = stackView;
+        mEnterAndExitFromHomeTranslationOffset = Recents.getConfiguration().isGridEnabled
+                ? 0 : DOUBLE_FRAME_OFFSET_MS;
     }
 
     /**
@@ -260,7 +263,7 @@
                 AnimationProps taskAnimation = new AnimationProps()
                         .setInitialPlayTime(AnimationProps.BOUNDS,
                                 Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS, taskIndexFromFront) *
-                                        DOUBLE_FRAME_OFFSET_MS)
+                                        mEnterAndExitFromHomeTranslationOffset)
                         .setStartDelay(AnimationProps.ALPHA,
                                 Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS, taskIndexFromFront) *
                                         FRAME_OFFSET_MS)
@@ -321,7 +324,7 @@
             AnimationProps taskAnimation;
             if (animated) {
                 int delay = Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS , taskIndexFromFront) *
-                        DOUBLE_FRAME_OFFSET_MS;
+                        mEnterAndExitFromHomeTranslationOffset;
                 taskAnimation = new AnimationProps()
                         .setStartDelay(AnimationProps.BOUNDS, delay)
                         .setDuration(AnimationProps.BOUNDS, EXIT_TO_HOME_TRANSLATION_DURATION)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 3499dfd..4fa7ecb5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -213,38 +213,10 @@
     }
 
     /**
-     * The state telling the algorithm whether to use grid layout or not.
+     * @return True if we should use the grid layout.
      */
-    public static class GridState {
-        private boolean mDraggingOverDockedState;
-        private boolean mHasDockedTask;
-
-        private GridState() {
-            mDraggingOverDockedState = false;
-            mHasDockedTask = false;
-        }
-
-        /**
-         * Check whether we should use the grid layout.
-         * We use the grid layout for Recents iff all the following is true:
-         *  1. Grid-mode is enabled.
-         *  2. The activity is not in split screen mode (there's no docked task).
-         *  3. The user is not dragging a task view over the dock state.
-         * @return True if we should use the grid layout.
-         */
-        boolean useGridLayout() {
-            return Recents.getConfiguration().isGridEnabled &&
-                !mDraggingOverDockedState &&
-                !mHasDockedTask;
-        }
-
-        public void setDragging(boolean draggingOverDockedState) {
-            mDraggingOverDockedState = draggingOverDockedState;
-        }
-
-        public void setHasDockedTasks(boolean hasDockedTask) {
-            mHasDockedTask = hasDockedTask;
-        }
+    boolean useGridLayout() {
+        return Recents.getConfiguration().isGridEnabled;
     }
 
     // A report of the visibility state of the stack
@@ -261,7 +233,6 @@
 
     Context mContext;
     private StackState mState = StackState.SPLIT;
-    private GridState mGridState = new GridState();
     private TaskStackLayoutAlgorithmCallbacks mCb;
 
     // The task bounds (untransformed) for layout.  This rect is anchored at mTaskRoot.
@@ -320,6 +291,9 @@
     @ViewDebug.ExportedProperty(category="recents")
     private int mStackBottomOffset;
 
+    /** The height, in pixels, of each task view's title bar. */
+    private int mTitleBarHeight;
+
     // The paths defining the motion of the tasks when the stack is focused and unfocused
     private Path mUnfocusedCurve;
     private Path mFocusedCurve;
@@ -432,6 +406,14 @@
         mBaseBottomMargin = res.getDimensionPixelSize(R.dimen.recents_layout_bottom_margin);
         mFreeformStackGap =
                 res.getDimensionPixelSize(R.dimen.recents_freeform_layout_bottom_margin);
+        mTitleBarHeight = getDimensionForDevice(mContext,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height_tablet_land,
+                R.dimen.recents_task_view_header_height,
+                R.dimen.recents_task_view_header_height_tablet_land,
+                R.dimen.recents_grid_task_view_header_height);
     }
 
     /**
@@ -516,7 +498,7 @@
         }
 
         // Initialize the grid layout
-        mTaskGridLayoutAlgorithm.initialize(displayRect, windowRect);
+        mTaskGridLayoutAlgorithm.initialize(windowRect);
     }
 
     /**
@@ -769,7 +751,7 @@
     }
 
     public Rect getStackActionButtonRect() {
-        return mGridState.useGridLayout()
+        return useGridLayout()
                 ? mTaskGridLayoutAlgorithm.getStackActionButtonRect() : mStackActionButtonRect;
     }
 
@@ -795,13 +777,6 @@
     }
 
     /**
-     * Returns the current grid layout state.
-     */
-    public GridState getGridState() {
-        return mGridState;
-    }
-
-    /**
      * Returns whether this stack layout has been initialized.
      */
     public boolean isInitialized() {
@@ -902,7 +877,7 @@
         if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) {
             mFreeformLayoutAlgorithm.getTransform(task, transformOut, this);
             return transformOut;
-        } else if (mGridState.useGridLayout()) {
+        } else if (useGridLayout()) {
             int taskIndex = mTaskIndexMap.get(task.key.id);
             int taskCount = mTaskIndexMap.size();
             mTaskGridLayoutAlgorithm.getTransform(taskIndex, taskCount, transformOut, this);
@@ -939,12 +914,17 @@
      * Transforms the given {@param transformOut} to the screen coordinates, overriding the current
      * window rectangle with {@param windowOverrideRect} if non-null.
      */
-    public TaskViewTransform transformToScreenCoordinates(TaskViewTransform transformOut,
+    TaskViewTransform transformToScreenCoordinates(TaskViewTransform transformOut,
             Rect windowOverrideRect) {
         Rect windowRect = windowOverrideRect != null
                 ? windowOverrideRect
                 : Recents.getSystemServices().getWindowRect();
         transformOut.rect.offset(windowRect.left, windowRect.top);
+        if (useGridLayout()) {
+            // Draw the thumbnail a little lower to perfectly coincide with the view we are
+            // transitioning to, where the header bar has already been drawn.
+            transformOut.rect.offset(0, mTitleBarHeight);
+        }
         return transformOut;
     }
 
@@ -1323,7 +1303,7 @@
      * Returns the proper task rectangle according to the current grid state.
      */
     public Rect getTaskRect() {
-        return mGridState.useGridLayout() ? mTaskGridLayoutAlgorithm.getTaskGridRect() : mTaskRect;
+        return useGridLayout() ? mTaskGridLayoutAlgorithm.getTaskGridRect() : mTaskRect;
     }
 
     public void dump(String prefix, PrintWriter writer) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 326a280..fc2550a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -70,6 +70,7 @@
 import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.events.activity.ShowStackActionButtonEvent;
+import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
 import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
 import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
@@ -93,6 +94,7 @@
 import com.android.systemui.recents.model.TaskStack;
 
 import com.android.systemui.recents.views.grid.GridTaskView;
+import com.android.systemui.recents.views.grid.TaskViewFocusFrame;
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -206,6 +208,10 @@
     private int mLastWidth;
     private int mLastHeight;
 
+    // We keep track of the task view focused by user interaction and draw a frame around it in the
+    // grid layout.
+    private TaskViewFocusFrame mTaskViewFocusFrame;
+
     // A convenience update listener to request updating clipping of tasks
     private ValueAnimator.AnimatorUpdateListener mRequestUpdateClippingListener =
             new ValueAnimator.AnimatorUpdateListener() {
@@ -265,6 +271,14 @@
         mDisplayOrientation = Utilities.getAppConfiguration(mContext).orientation;
         mDisplayRect = ssp.getDisplayRect();
 
+        // Create a frame to draw around the focused task view
+        if (Recents.getConfiguration().isGridEnabled) {
+            mTaskViewFocusFrame = new TaskViewFocusFrame(mContext, this,
+                mLayoutAlgorithm.mTaskGridLayoutAlgorithm);
+            addView(mTaskViewFocusFrame);
+            getViewTreeObserver().addOnGlobalFocusChangeListener(mTaskViewFocusFrame);
+        }
+
         int taskBarDismissDozeDelaySeconds = getResources().getInteger(
                 R.integer.recents_task_bar_dismiss_delay_seconds);
         mUIDozeTrigger = new DozeTrigger(taskBarDismissDozeDelaySeconds, new Runnable() {
@@ -878,7 +892,7 @@
      *
      * @return whether or not the stack will scroll as a part of this focus change
      */
-    private boolean setFocusedTask(int taskIndex, boolean scrollToTask,
+    public boolean setFocusedTask(int taskIndex, boolean scrollToTask,
             final boolean requestViewFocus) {
         return setFocusedTask(taskIndex, scrollToTask, requestViewFocus, 0);
     }
@@ -888,7 +902,7 @@
      *
      * @return whether or not the stack will scroll as a part of this focus change
      */
-    private boolean setFocusedTask(int focusTaskIndex, boolean scrollToTask,
+    public boolean setFocusedTask(int focusTaskIndex, boolean scrollToTask,
             boolean requestViewFocus, int timerIndicatorDuration) {
         // Find the next task to focus
         int newFocusedTaskIndex = mStack.getTaskCount() > 0 ?
@@ -940,6 +954,10 @@
                     newFocusedTaskView.setFocusedState(true, requestViewFocus);
                 }
             }
+            // Any time a task view gets the focus, we move the focus frame around it.
+            if (mTaskViewFocusFrame != null) {
+                mTaskViewFocusFrame.moveGridTaskViewFocus(getChildViewForTask(newFocusedTask));
+            }
         }
         return willScroll;
     }
@@ -1005,20 +1023,28 @@
             float stackScroll = mStackScroller.getStackScroll();
             ArrayList<Task> tasks = mStack.getStackTasks();
             int taskCount = tasks.size();
-            if (forward) {
-                // Walk backwards and focus the next task smaller than the current stack scroll
-                for (newIndex = taskCount - 1; newIndex >= 0; newIndex--) {
-                    float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
-                    if (Float.compare(taskP, stackScroll) <= 0) {
-                        break;
-                    }
-                }
+            if (useGridLayout()) {
+                // For the grid layout, we directly set focus to the most recently used task
+                // no matter we're moving forwards or backwards.
+                newIndex = taskCount - 1;
             } else {
-                // Walk forwards and focus the next task larger than the current stack scroll
-                for (newIndex = 0; newIndex < taskCount; newIndex++) {
-                    float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
-                    if (Float.compare(taskP, stackScroll) >= 0) {
-                        break;
+                // For the grid layout we pick a proper task to focus, according to the current
+                // stack scroll.
+                if (forward) {
+                    // Walk backwards and focus the next task smaller than the current stack scroll
+                    for (newIndex = taskCount - 1; newIndex >= 0; newIndex--) {
+                        float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
+                        if (Float.compare(taskP, stackScroll) <= 0) {
+                            break;
+                        }
+                    }
+                } else {
+                    // Walk forwards and focus the next task larger than the current stack scroll
+                    for (newIndex = 0; newIndex < taskCount; newIndex++) {
+                        float taskP = mLayoutAlgorithm.getStackScrollForTask(tasks.get(newIndex));
+                        if (Float.compare(taskP, stackScroll) >= 0) {
+                            break;
+                        }
                     }
                 }
             }
@@ -1037,20 +1063,23 @@
     /**
      * Resets the focused task.
      */
-    void resetFocusedTask(Task task) {
+    public void resetFocusedTask(Task task) {
         if (task != null) {
             TaskView tv = getChildViewForTask(task);
             if (tv != null) {
                 tv.setFocusedState(false, false /* requestViewFocus */);
             }
         }
+        if (mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.moveGridTaskViewFocus(null);
+        }
         mFocusedTask = null;
     }
 
     /**
      * Returns the focused task.
      */
-    Task getFocusedTask() {
+    public Task getFocusedTask() {
         return mFocusedTask;
     }
 
@@ -1253,6 +1282,9 @@
         for (int i = 0; i < taskViewCount; i++) {
             measureTaskView(mTmpTaskViews.get(i));
         }
+        if (mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.measure();
+        }
 
         setMeasuredDimension(width, height);
         mLastWidth = width;
@@ -1287,6 +1319,9 @@
         for (int i = 0; i < taskViewCount; i++) {
             layoutTaskView(changed, mTmpTaskViews.get(i));
         }
+        if (mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.layout();
+        }
 
         if (changed) {
             if (mStackScroller.isScrollOutOfBounds()) {
@@ -1339,10 +1374,19 @@
         // until after the enter-animation
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
-        int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getTaskCount());
-        if (focusedTaskIndex != -1) {
-            setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
-                    false /* requestViewFocus */);
+
+        // We set the initial focused task view iff the following conditions are satisfied:
+        // 1. Recents is showing task views in stack layout.
+        // 2. Recents is launched with ALT + TAB.
+        boolean setFocusOnFirstLayout = !useGridLayout() ||
+            Recents.getConfiguration().getLaunchState().launchedWithAltTab;
+        if (setFocusOnFirstLayout) {
+            int focusedTaskIndex = launchState.getInitialFocusTaskIndex(mStack.getTaskCount(),
+                useGridLayout());
+            if (focusedTaskIndex != -1) {
+                setFocusedTask(focusedTaskIndex, false /* scrollToTask */,
+                        false /* requestViewFocus */);
+            }
         }
         updateStackActionButtonVisibility();
     }
@@ -1443,6 +1487,11 @@
         // Remove the task from the ignored set
         removeIgnoreTask(removedTask);
 
+        // Resize the grid layout task view focus frame
+        if (mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.resize();
+        }
+
         // If requested, relayout with the given animation
         if (animation != null) {
             updateLayoutAlgorithm(true /* boundScroll */);
@@ -1740,10 +1789,18 @@
         int taskViewExitToHomeDuration = TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION;
         animateFreeformWorkspaceBackgroundAlpha(0, new AnimationProps(taskViewExitToHomeDuration,
                 Interpolators.FAST_OUT_SLOW_IN));
+
+        // Dismiss the grid task view focus frame
+        if (mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.moveGridTaskViewFocus(null);
+        }
     }
 
     public final void onBusEvent(DismissFocusedTaskViewEvent event) {
         if (mFocusedTask != null) {
+            if (mTaskViewFocusFrame != null) {
+                mTaskViewFocusFrame.moveGridTaskViewFocus(null);
+            }
             TaskView tv = getChildViewForTask(mFocusedTask);
             if (tv != null) {
                 tv.dismissTask();
@@ -1858,7 +1915,6 @@
                 Interpolators.FAST_OUT_SLOW_IN);
         boolean ignoreTaskOverrides = false;
         if (event.dropTarget instanceof TaskStack.DockState) {
-            mLayoutAlgorithm.getGridState().setDragging(true);
             // Calculate the new task stack bounds that matches the window size that Recents will
             // have after the drop
             final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
@@ -1878,7 +1934,6 @@
             updateLayoutAlgorithm(true /* boundScroll */);
             ignoreTaskOverrides = true;
         } else {
-            mLayoutAlgorithm.getGridState().setDragging(false);
             // Restore the pre-drag task stack bounds, but ensure that we don't layout the dragging
             // task view, so add it back to the ignore set after updating the layout
             removeIgnoreTask(event.task);
@@ -1889,7 +1944,6 @@
     }
 
     public final void onBusEvent(final DragEndEvent event) {
-        mLayoutAlgorithm.getGridState().setDragging(false);
         // We don't handle drops on the dock regions
         if (event.dropTarget instanceof TaskStack.DockState) {
             // However, we do need to reset the overrides, since the last state of this task stack
@@ -2076,13 +2130,17 @@
         mResetToInitialStateWhenResized = true;
     }
 
+    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
+        if (!event.visible && mTaskViewFocusFrame != null) {
+            mTaskViewFocusFrame.moveGridTaskViewFocus(null);
+        }
+    }
+
     public void reloadOnConfigurationChange() {
         mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
         mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
 
         boolean hasDockedTask = Recents.getSystemServices().hasDockedTask();
-        mStableLayoutAlgorithm.getGridState().setHasDockedTasks(hasDockedTask);
-        mLayoutAlgorithm.getGridState().setHasDockedTasks(hasDockedTask);
     }
 
     /**
@@ -2139,7 +2197,7 @@
      * Check whether we should use the grid layout.
      */
     public boolean useGridLayout() {
-        return mLayoutAlgorithm.getGridState().useGridLayout();
+        return mLayoutAlgorithm.useGridLayout();
     }
 
     /**
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 33fa3b0..5817e92 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -342,8 +342,9 @@
                         mSv.invalidate();
                     }
 
-                    // Reset the focused task after the user has scrolled
-                    if (!mSv.mTouchExplorationEnabled) {
+                    // Reset the focused task after the user has scrolled, but we have no scrolling
+                    // in grid layout and therefore we don't want to reset the focus there.
+                    if (!mSv.mTouchExplorationEnabled && !mSv.useGridLayout()) {
                         mSv.resetFocusedTask(mSv.getFocusedTask());
                     }
                 } else if (mActiveTaskView == null) {
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 5f37349..e41a718 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -22,7 +22,6 @@
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
-import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Outline;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index e3bf1df..bae5daa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -35,6 +35,9 @@
 import android.view.ViewDebug;
 
 import com.android.systemui.R;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.EventBus.Event;
+import com.android.systemui.recents.events.ui.TaskSnapshotChangedEvent;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.ThumbnailData;
@@ -347,6 +350,7 @@
             mBgFillPaint.setColor(t.colorBackground);
         }
         mLockedPaint.setColor(t.colorPrimary);
+        EventBus.getDefault().register(this);
     }
 
     /**
@@ -361,6 +365,14 @@
     void unbindFromTask() {
         mTask = null;
         setThumbnail(null);
+        EventBus.getDefault().unregister(this);
+    }
+
+    public final void onBusEvent(TaskSnapshotChangedEvent event) {
+        if (mTask == null || event.taskId != mTask.key.id || event.taskSnapshot == null) {
+            return;
+        }
+        setThumbnail(ThumbnailData.createFromTaskSnapshot(event.taskSnapshot));
     }
 
     public void dump(String prefix, PrintWriter writer) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
index 5d969f9..70536b1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java
@@ -39,7 +39,6 @@
     /** The padding between task views. */
     private int mPaddingTaskView;
 
-    private Rect mDisplayRect;
     private Rect mWindowRect;
     private Point mScreenSize = new Point();
 
@@ -52,6 +51,9 @@
     private float mAppAspectRatio;
     private Rect mSystemInsets = new Rect();
 
+    /** The thickness of the focused task view frame. */
+    private int mFocusedFrameThickness;
+
     /**
      * When the amount of tasks is determined, the size and position of every task view can be
      * decided. Each instance of TaskGridRectInfo store the task view information for a certain
@@ -62,7 +64,7 @@
         int[] xOffsets;
         int[] yOffsets;
 
-        public TaskGridRectInfo(int taskCount) {
+        TaskGridRectInfo(int taskCount) {
             size = new Rect();
             xOffsets = new int[taskCount];
             yOffsets = new int[taskCount];
@@ -74,10 +76,26 @@
                     layoutTaskCount < 7 ? 3 : 4));
             int lines = layoutTaskCount < 3 ? 1 : 2;
 
+            // A couple of special cases.
+            boolean landscapeWindow = mWindowRect.width() > mWindowRect.height();
+            boolean landscapeTaskView = mAppAspectRatio > 1;
+            // If we're in portrait but task views are landscape, show more lines of fewer tasks.
+            if (!landscapeWindow && landscapeTaskView) {
+                tasksPerLine = layoutTaskCount < 2 ? 1 : 2;
+                lines = layoutTaskCount < 3 ? 1 : (
+                        layoutTaskCount < 5 ? 2 : (
+                                layoutTaskCount < 7 ? 3 : 4));
+            }
+            // If we're in landscape but task views are portrait, show fewer lines of more tasks.
+            if (landscapeWindow && !landscapeTaskView) {
+                tasksPerLine = layoutTaskCount < 7 ? layoutTaskCount : 6;
+                lines = layoutTaskCount < 7 ? 1 : 2;
+            }
+
             int taskWidth, taskHeight;
-            int maxTaskWidth = (mDisplayRect.width() - 2 * mPaddingLeftRight
+            int maxTaskWidth = (mWindowRect.width() - 2 * mPaddingLeftRight
                 - (tasksPerLine - 1) * mPaddingTaskView) / tasksPerLine;
-            int maxTaskHeight = (mDisplayRect.height() - 2 * mPaddingTopBottom
+            int maxTaskHeight = (mWindowRect.height() - 2 * mPaddingTopBottom
                 - (lines - 1) * mPaddingTaskView) / lines;
 
             if (maxTaskHeight >= maxTaskWidth / mAppAspectRatio + mTitleBarHeight) {
@@ -91,9 +109,9 @@
             }
             size.set(0, 0, taskWidth, taskHeight);
 
-            int emptySpaceX = mDisplayRect.width() - 2 * mPaddingLeftRight
+            int emptySpaceX = mWindowRect.width() - 2 * mPaddingLeftRight
                 - (tasksPerLine * taskWidth) - (tasksPerLine - 1) * mPaddingTaskView;
-            int emptySpaceY = mDisplayRect.height() - 2 * mPaddingTopBottom
+            int emptySpaceY = mWindowRect.height() - 2 * mPaddingTopBottom
                 - (lines * taskHeight) - (lines - 1) * mPaddingTaskView;
             for (int taskIndex = 0; taskIndex < taskCount; taskIndex++) {
                 // We also need to invert the index in order to display the most recent tasks first.
@@ -101,9 +119,9 @@
 
                 int xIndex = taskLayoutIndex % tasksPerLine;
                 int yIndex = taskLayoutIndex / tasksPerLine;
-                xOffsets[taskIndex] =
+                xOffsets[taskIndex] = mWindowRect.left +
                     emptySpaceX / 2 + mPaddingLeftRight + (taskWidth + mPaddingTaskView) * xIndex;
-                yOffsets[taskIndex] =
+                yOffsets[taskIndex] = mWindowRect.top +
                     emptySpaceY / 2 + mPaddingTopBottom + (taskHeight + mPaddingTaskView) * yIndex;
             }
         }
@@ -113,7 +131,7 @@
      * We can find task view sizes and positions from mTaskGridRectInfoList[k - 1] when there
      * are k tasks.
      */
-    TaskGridRectInfo[] mTaskGridRectInfoList;
+    private TaskGridRectInfo[] mTaskGridRectInfoList;
 
     public TaskGridLayoutAlgorithm(Context context) {
         reloadOnConfigurationChange(context);
@@ -121,9 +139,9 @@
 
     public void reloadOnConfigurationChange(Context context) {
         Resources res = context.getResources();
-        mPaddingLeftRight = res.getDimensionPixelSize(R.dimen.recents_grid_padding_left_right);
-        mPaddingTopBottom = res.getDimensionPixelSize(R.dimen.recents_grid_padding_top_bottom);
         mPaddingTaskView = res.getDimensionPixelSize(R.dimen.recents_grid_padding_task_view);
+        mFocusedFrameThickness = res.getDimensionPixelSize(
+            R.dimen.recents_grid_task_view_focused_frame_thickness);
 
         mTaskGridRect = new Rect();
         mTitleBarHeight = res.getDimensionPixelSize(R.dimen.recents_grid_task_view_header_height);
@@ -147,6 +165,10 @@
      */
     public TaskViewTransform getTransform(int taskIndex, int taskCount,
         TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) {
+        if (taskCount == 0) {
+            transformOut.reset();
+            return transformOut;
+        }
 
         TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1];
         mTaskGridRect.set(gridInfo.size);
@@ -162,7 +184,7 @@
 
         // We also need to invert the index in order to display the most recent tasks first.
         int taskLayoutIndex = taskCount - taskIndex - 1;
-        boolean isTaskViewVisible = (taskLayoutIndex < MAX_LAYOUT_TASK_COUNT);
+        boolean isTaskViewVisible = taskLayoutIndex < MAX_LAYOUT_TASK_COUNT;
 
         // Fill out the transform
         transformOut.scale = 1f;
@@ -178,9 +200,11 @@
         return transformOut;
     }
 
-    public void initialize(Rect displayRect, Rect windowRect) {
-        mDisplayRect = displayRect;
+    public void initialize(Rect windowRect) {
         mWindowRect = windowRect;
+        // Define paddings in terms of percentage of the total area.
+        mPaddingLeftRight = (int) (0.025f * Math.min(mWindowRect.width(), mWindowRect.height()));
+        mPaddingTopBottom = (int) (0.1 * mWindowRect.height());
 
         // Pre-calculate the positions and offsets of task views so that we can reuse them directly
         // in the future.
@@ -202,14 +226,25 @@
     }
 
     public Rect getStackActionButtonRect() {
-        Rect buttonRect = new Rect(mDisplayRect);
+        Rect buttonRect = new Rect(mWindowRect);
         buttonRect.right -= mPaddingLeftRight;
         buttonRect.left += mPaddingLeftRight;
         buttonRect.bottom = buttonRect.top + mPaddingTopBottom;
         return buttonRect;
     }
 
+    public void updateTaskGridRect(int taskCount) {
+        if (taskCount > 0) {
+            TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1];
+            mTaskGridRect.set(gridInfo.size);
+        }
+    }
+
     public Rect getTaskGridRect() {
         return mTaskGridRect;
     }
+
+    public int getFocusFrameThickness() {
+        return mFocusedFrameThickness;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
new file mode 100644
index 0000000..86ed583
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskViewFocusFrame.java
@@ -0,0 +1,141 @@
+/*
+ * 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.recents.views.grid;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import android.view.ViewTreeObserver.OnGlobalFocusChangeListener;
+import com.android.systemui.R;
+import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.views.TaskStackView;
+
+public class TaskViewFocusFrame extends View implements OnGlobalFocusChangeListener {
+
+    private TaskStackView mSv;
+    private TaskGridLayoutAlgorithm mTaskGridLayoutAlgorithm;
+    public TaskViewFocusFrame(Context context) {
+        this(context, null);
+    }
+
+    public TaskViewFocusFrame(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public TaskViewFocusFrame(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public TaskViewFocusFrame(Context context, AttributeSet attrs, int defStyleAttr,
+        int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        setBackground(mContext.getDrawable(
+            R.drawable.recents_grid_task_view_focus_frame_background));
+        setFocusable(false);
+        hide();
+    }
+
+    public TaskViewFocusFrame(Context context, TaskStackView stackView,
+        TaskGridLayoutAlgorithm taskGridLayoutAlgorithm) {
+        this(context);
+        mSv = stackView;
+        mTaskGridLayoutAlgorithm = taskGridLayoutAlgorithm;
+    }
+
+    /**
+     * Measure the width and height of the focus frame according to the current grid task view size.
+     */
+    public void measure() {
+        int thickness = mTaskGridLayoutAlgorithm.getFocusFrameThickness();
+        Rect rect = mTaskGridLayoutAlgorithm.getTaskGridRect();
+        measure(
+            MeasureSpec.makeMeasureSpec(rect.width() + thickness * 2, MeasureSpec.EXACTLY),
+            MeasureSpec.makeMeasureSpec(rect.height() + thickness * 2, MeasureSpec.EXACTLY));
+    }
+
+    /**
+     * Layout the focus frame with its size.
+     */
+    public void layout() {
+        layout(0, 0, getMeasuredWidth(), getMeasuredHeight());
+    }
+
+    /**
+     * Update the current size of grid task view and the focus frame.
+     */
+    public void resize() {
+        if (mSv.useGridLayout()) {
+            mTaskGridLayoutAlgorithm.updateTaskGridRect(mSv.getStack().getTaskCount());
+            measure();
+            requestLayout();
+        }
+    }
+
+    /**
+     * Move the task view focus frame to surround the newly focused view. If it's {@code null} or
+     * it's not an instance of GridTaskView, we hide the focus frame.
+     * @param newFocus The newly focused view.
+     */
+    public void moveGridTaskViewFocus(View newFocus) {
+        if (mSv.useGridLayout()) {
+            // The frame only shows up in the grid layout. It shouldn't show up in the stack
+            // layout including when we're in the split screen.
+            if (newFocus instanceof GridTaskView) {
+                // If the focus goes to a GridTaskView, we show the frame and layout it.
+                int[] location = new int[2];
+                newFocus.getLocationInWindow(location);
+                int thickness = mTaskGridLayoutAlgorithm.getFocusFrameThickness();
+                setTranslationX(location[0] - thickness);
+                setTranslationY(location[1] - thickness);
+                show();
+            } else {
+                // If focus goes to other views, we hide the frame.
+                hide();
+            }
+        }
+    }
+
+    @Override
+    public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+        if (!mSv.useGridLayout()) {
+            return;
+        }
+        if (newFocus == null) {
+            // We're going to touch mode, unset the focus.
+            moveGridTaskViewFocus(null);
+            return;
+        }
+        if (oldFocus == null) {
+            // We're returning from touch mode, set the focus to the previously focused task.
+            final TaskStack stack = mSv.getStack();
+            final int taskCount = stack.getTaskCount();
+            final int k = stack.indexOfStackTask(mSv.getFocusedTask());
+            final int taskIndexToFocus = k == -1 ? (taskCount - 1) : (k % taskCount);
+            mSv.setFocusedTask(taskIndexToFocus, false, true);
+        }
+    }
+
+    private void show() {
+        setAlpha(1f);
+    }
+
+    private void hide() {
+        setAlpha(0f);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index d1ab96d..b5358bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -182,6 +182,7 @@
     private int mStartTint;
     private int mOverrideTint;
     private float mOverrideAmount;
+    private boolean mShadowHidden;
 
     public ActivatableNotificationView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -210,6 +211,7 @@
         super.onFinishInflate();
         mBackgroundNormal = (NotificationBackgroundView) findViewById(R.id.backgroundNormal);
         mFakeShadow = (FakeShadowView) findViewById(R.id.fake_shadow);
+        mShadowHidden = mFakeShadow.getVisibility() != VISIBLE;
         mBackgroundDimmed = (NotificationBackgroundView) findViewById(R.id.backgroundDimmed);
         mBackgroundNormal.setCustomBackground(R.drawable.notification_material_bg);
         mBackgroundDimmed.setCustomBackground(R.drawable.notification_material_bg_dim);
@@ -249,7 +251,7 @@
     @Override
     public boolean onTouchEvent(MotionEvent event) {
         boolean result;
-        if (mDimmed && !isTouchExplorationEnabled()) {
+        if (mDimmed && !isTouchExplorationEnabled() && isInteractive()) {
             boolean wasActivated = mActivated;
             result = handleTouchEventDimmed(event);
             if (wasActivated && result && event.getAction() == MotionEvent.ACTION_UP) {
@@ -261,6 +263,13 @@
         return result;
     }
 
+    /**
+     * @return whether this view is interactive and can be double tapped
+     */
+    protected boolean isInteractive() {
+        return true;
+    }
+
     @Override
     public void drawableHotspotChanged(float x, float y) {
         if (!mDimmed){
@@ -1020,9 +1029,13 @@
     @Override
     public void setFakeShadowIntensity(float shadowIntensity, float outlineAlpha, int shadowYEnd,
             int outlineTranslation) {
-        mFakeShadow.setFakeShadowTranslationZ(shadowIntensity * (getTranslationZ()
-                + FakeShadowView.SHADOW_SIBLING_TRESHOLD), outlineAlpha, shadowYEnd,
-                outlineTranslation);
+        boolean hiddenBefore = mShadowHidden;
+        mShadowHidden = shadowIntensity == 0.0f;
+        if (!mShadowHidden || !hiddenBefore) {
+            mFakeShadow.setFakeShadowTranslationZ(shadowIntensity * (getTranslationZ()
+                            + FakeShadowView.SHADOW_SIBLING_TRESHOLD), outlineAlpha, shadowYEnd,
+                    outlineTranslation);
+        }
     }
 
     public int getBackgroundColorWithoutTint() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index db099bc..faf143e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -122,7 +122,7 @@
 public abstract class BaseStatusBar extends SystemUI implements
         CommandQueue.Callbacks, ActivatableNotificationView.OnActivatedListener,
         ExpandableNotificationRow.ExpansionLogger, NotificationData.Environment,
-        ExpandableNotificationRow.OnExpandClickListener, OnGutsClosedListener {
+        ExpandableNotificationRow.OnExpandClickListener {
     public static final String TAG = "StatusBar";
     public static final boolean DEBUG = false;
     public static final boolean MULTIUSER_DEBUG = false;
@@ -185,9 +185,6 @@
     protected int mLayoutDirection = -1; // invalid
     protected AccessibilityManager mAccessibilityManager;
 
-    // on-screen navigation buttons
-    protected NavigationBarView mNavigationBarView = null;
-
     protected boolean mDeviceInteractive;
 
     protected boolean mVisible;
@@ -238,8 +235,6 @@
     protected WindowManager mWindowManager;
     protected IWindowManager mWindowManagerService;
 
-    protected abstract void refreshLayout(int layoutDirection);
-
     protected Display mDisplay;
 
     private boolean mDeviceProvisioned = false;
@@ -945,8 +940,6 @@
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
-        final Locale locale = mContext.getResources().getConfiguration().locale;
-        final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
         final float fontScale = newConfig.fontScale;
         final int density = newConfig.densityDpi;
         if (density != mDensity || mFontScale != fontScale) {
@@ -954,16 +947,6 @@
             mDensity = density;
             mFontScale = fontScale;
         }
-        if (! locale.equals(mLocale) || ld != mLayoutDirection) {
-            if (DEBUG) {
-                Log.v(TAG, String.format(
-                        "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
-                        locale, ld));
-            }
-            mLocale = locale;
-            mLayoutDirection = ld;
-            refreshLayout(ld);
-        }
     }
 
     protected void onDensityOrFontScaleChanged() {
@@ -1058,7 +1041,12 @@
         PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
         row.setTag(sbn.getPackageName());
         final NotificationGuts guts = row.getGuts();
-        guts.setClosedListener(this);
+        guts.setClosedListener((NotificationGuts g) -> {
+            if (!row.isRemoved()) {
+                mStackScroller.onHeightChanged(row, !isPanelFullyCollapsed() /* needsAnimation */);
+            }
+            mNotificationGutsExposed = null;
+        });
 
         final INotificationManager iNotificationManager = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -1144,6 +1132,11 @@
                 // Post to ensure the the guts are properly laid out.
                 guts.post(new Runnable() {
                     public void run() {
+                        if (row.getWindowToken() == null) {
+                            Log.e(TAG, "Trying to show notification guts, but not attached to "
+                                    + "window");
+                            return;
+                        }
                         dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */,
                                 false /* animate */);
                         guts.setVisibility(View.VISIBLE);
@@ -1166,7 +1159,7 @@
                         guts.setExposed(true /* exposed */,
                                 mState == StatusBarState.KEYGUARD /* needsFalsingProtection */);
                         row.closeRemoteInput();
-                        mStackScroller.onHeightChanged(null, true /* needsAnimation */);
+                        mStackScroller.onHeightChanged(row, true /* needsAnimation */);
                         mNotificationGutsExposed = guts;
                     }
                 });
@@ -1200,12 +1193,6 @@
     }
 
     @Override
-    public void onGutsClosed(NotificationGuts guts) {
-        mStackScroller.onHeightChanged(null, true /* needsAnimation */);
-        mNotificationGutsExposed = null;
-    }
-
-    @Override
     public void showRecentApps(boolean triggeredFromAltTab, boolean fromHome) {
         int msg = MSG_SHOW_RECENT_APPS;
         mHandler.removeMessages(msg);
@@ -1285,26 +1272,6 @@
 
     protected abstract View getStatusBarView();
 
-    protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
-        // additional optimization when we have software system buttons - start loading the recent
-        // tasks on touch down
-        @Override
-        public boolean onTouch(View v, MotionEvent event) {
-            int action = event.getAction() & MotionEvent.ACTION_MASK;
-            if (action == MotionEvent.ACTION_DOWN) {
-                preloadRecents();
-            } else if (action == MotionEvent.ACTION_CANCEL) {
-                cancelPreloadingRecents();
-            } else if (action == MotionEvent.ACTION_UP) {
-                if (!v.isPressed()) {
-                    cancelPreloadingRecents();
-                }
-
-            }
-            return false;
-        }
-    };
-
     /**
      * Toggle docking the app window
      *
@@ -1557,6 +1524,7 @@
         final RemoteViews bigContentView = entry.cachedBigContentView;
         final RemoteViews headsUpContentView = entry.cachedHeadsUpContentView;
         final RemoteViews publicContentView = entry.cachedPublicContentView;
+        final RemoteViews ambientContentView = entry.cachedAmbientContentView;
 
         if (contentView == null) {
             Log.v(TAG, "no contentView for: " + sbn.getNotification());
@@ -1637,6 +1605,7 @@
         View bigContentViewLocal = null;
         View headsUpContentViewLocal = null;
         View publicViewLocal = null;
+        View ambientViewLocal = null;
         try {
             contentViewLocal = contentView.apply(
                     sbn.getPackageContext(mContext),
@@ -1659,6 +1628,11 @@
                         sbn.getPackageContext(mContext),
                         contentContainerPublic, mOnClickHandler);
             }
+            if (ambientContentView != null) {
+                ambientViewLocal = ambientContentView.apply(
+                        sbn.getPackageContext(mContext),
+                        contentContainer, mOnClickHandler);
+            }
 
             if (contentViewLocal != null) {
                 contentViewLocal.setIsRootNamespace(true);
@@ -1676,6 +1650,11 @@
                 publicViewLocal.setIsRootNamespace(true);
                 contentContainerPublic.setContractedChild(publicViewLocal);
             }
+
+            if (ambientViewLocal != null) {
+                ambientViewLocal.setIsRootNamespace(true);
+                contentContainer.setAmbientChild(ambientViewLocal);
+            }
         }
         catch (RuntimeException e) {
             final String ident = sbn.getPackageName() + "/0x" + Integer.toHexString(sbn.getId());
@@ -2172,6 +2151,7 @@
                 row.setOnKeyguard(false);
                 row.setSystemExpanded(visibleNotifications == 0 && !childNotification);
             }
+            entry.row.setShowAmbient(isDozing());
             int userId = entry.notification.getUserId();
             boolean suppressedSummary = mGroupManager.isSummaryOfSuppressedGroup(
                     entry.notification) && !entry.row.isRemoved();
@@ -2209,6 +2189,10 @@
         mStackScroller.changeViewPosition(mNotificationShelf, mStackScroller.getChildCount() - 3);
     }
 
+    public boolean isDozing() {
+        return false;
+    }
+
     public boolean shouldShowOnKeyguard(StatusBarNotification sbn) {
         return mShowLockscreenNotifications && !mNotificationData.isAmbient(sbn.getKey());
     }
@@ -2256,7 +2240,6 @@
 
     protected abstract void setAreThereNotifications();
     protected abstract void updateNotifications();
-    public abstract boolean shouldDisableNavbarGestures();
 
     public abstract void addNotification(StatusBarNotification notification,
             RankingMap ranking, Entry oldEntry);
@@ -2422,7 +2405,7 @@
             Log.d(TAG, "failed to query dream manager", e);
         }
 
-        if (!inUse) {
+        if (!inUse && !isDozing()) {
             if (DEBUG) {
                 Log.d(TAG, "No peeking: not in use: " + sbn.getKey());
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index a3e4d5b..fed28e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -32,6 +32,8 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.systemui.SystemUI;
 
+import java.util.ArrayList;
+
 /**
  * This class takes the functions from IStatusBar that come in on
  * binder pool threads and posts messages to get them onto the main
@@ -91,7 +93,7 @@
     private static final String SHOW_IME_SWITCHER_KEY = "showImeSwitcherKey";
 
     private final Object mLock = new Object();
-    private Callbacks[] mCallbacks = new Callbacks[0];
+    private ArrayList<Callbacks> mCallbacks = new ArrayList<>();
     private Handler mHandler = new H(Looper.getMainLooper());
 
     /**
@@ -144,15 +146,11 @@
     }
 
     public void addCallbacks(Callbacks callbacks) {
-        Callbacks[] newArray = new Callbacks[mCallbacks.length + 1];
-        for (int i = 0; i < newArray.length - 1; i++) {
-            newArray[i] = mCallbacks[i];
-            if (newArray[i] == callbacks) {
-                throw new IllegalArgumentException("Callback was already added");
-            }
-        }
-        newArray[newArray.length - 1] = callbacks;
-        mCallbacks = newArray;
+        mCallbacks.add(callbacks);
+    }
+
+    public void removeCallbacks(Callbacks callbacks) {
+        mCallbacks.remove(callbacks);
     }
 
     public void setIcon(String slot, StatusBarIcon icon) {
@@ -427,182 +425,182 @@
                     switch (msg.arg1) {
                         case OP_SET_ICON: {
                             Pair<String, StatusBarIcon> p = (Pair<String, StatusBarIcon>) msg.obj;
-                            for (int i = 0; i < mCallbacks.length; i++) {
-                                mCallbacks[i].setIcon(p.first, p.second);
+                            for (int i = 0; i < mCallbacks.size(); i++) {
+                                mCallbacks.get(i).setIcon(p.first, p.second);
                             }
                             break;
                         }
                         case OP_REMOVE_ICON:
-                            for (int i = 0; i < mCallbacks.length; i++) {
-                                mCallbacks[i].removeIcon((String) msg.obj);
+                            for (int i = 0; i < mCallbacks.size(); i++) {
+                                mCallbacks.get(i).removeIcon((String) msg.obj);
                             }
                             break;
                     }
                     break;
                 }
                 case MSG_DISABLE:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].disable(msg.arg1, msg.arg2, true /* animate */);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).disable(msg.arg1, msg.arg2, true /* animate */);
                     }
                     break;
                 case MSG_EXPAND_NOTIFICATIONS:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].animateExpandNotificationsPanel();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).animateExpandNotificationsPanel();
                     }
                     break;
                 case MSG_COLLAPSE_PANELS:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].animateCollapsePanels(0);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).animateCollapsePanels(0);
                     }
                     break;
                 case MSG_EXPAND_SETTINGS:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].animateExpandSettingsPanel((String) msg.obj);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).animateExpandSettingsPanel((String) msg.obj);
                     }
                     break;
                 case MSG_SET_SYSTEMUI_VISIBILITY:
                     SomeArgs args = (SomeArgs) msg.obj;
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).setSystemUiVisibility(args.argi1, args.argi2, args.argi3,
                                 args.argi4, (Rect) args.arg1, (Rect) args.arg2);
                     }
                     args.recycle();
                     break;
                 case MSG_TOP_APP_WINDOW_CHANGED:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].topAppWindowChanged(msg.arg1 != 0);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).topAppWindowChanged(msg.arg1 != 0);
                     }
                     break;
                 case MSG_SHOW_IME_BUTTON:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).setImeWindowStatus((IBinder) msg.obj, msg.arg1, msg.arg2,
                                 msg.getData().getBoolean(SHOW_IME_SWITCHER_KEY, false));
                     }
                     break;
                 case MSG_SHOW_RECENT_APPS:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].showRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).showRecentApps(msg.arg1 != 0, msg.arg2 != 0);
                     }
                     break;
                 case MSG_HIDE_RECENT_APPS:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].hideRecentApps(msg.arg1 != 0, msg.arg2 != 0);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).hideRecentApps(msg.arg1 != 0, msg.arg2 != 0);
                     }
                     break;
                 case MSG_TOGGLE_RECENT_APPS:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].toggleRecentApps();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).toggleRecentApps();
                     }
                     break;
                 case MSG_PRELOAD_RECENT_APPS:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].preloadRecentApps();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).preloadRecentApps();
                     }
                     break;
                 case MSG_CANCEL_PRELOAD_RECENT_APPS:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].cancelPreloadRecentApps();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).cancelPreloadRecentApps();
                     }
                     break;
                 case MSG_DISMISS_KEYBOARD_SHORTCUTS:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].dismissKeyboardShortcutsMenu();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).dismissKeyboardShortcutsMenu();
                     }
                     break;
                 case MSG_TOGGLE_KEYBOARD_SHORTCUTS:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].toggleKeyboardShortcutsMenu(msg.arg1);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).toggleKeyboardShortcutsMenu(msg.arg1);
                     }
                     break;
                 case MSG_SET_WINDOW_STATE:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].setWindowState(msg.arg1, msg.arg2);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).setWindowState(msg.arg1, msg.arg2);
                     }
                     break;
                 case MSG_BUZZ_BEEP_BLINKED:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].buzzBeepBlinked();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).buzzBeepBlinked();
                     }
                     break;
                 case MSG_NOTIFICATION_LIGHT_OFF:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].notificationLightOff();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).notificationLightOff();
                     }
                     break;
                 case MSG_NOTIFICATION_LIGHT_PULSE:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).notificationLightPulse((Integer) msg.obj, msg.arg1, msg.arg2);
                     }
                     break;
                 case MSG_SHOW_SCREEN_PIN_REQUEST:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].showScreenPinningRequest(msg.arg1);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).showScreenPinningRequest(msg.arg1);
                     }
                     break;
                 case MSG_APP_TRANSITION_PENDING:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].appTransitionPending();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).appTransitionPending();
                     }
                     break;
                 case MSG_APP_TRANSITION_CANCELLED:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].appTransitionCancelled();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).appTransitionCancelled();
                     }
                     break;
                 case MSG_APP_TRANSITION_STARTING:
-                    for (int i = 0; i < mCallbacks.length; i++) {
+                    for (int i = 0; i < mCallbacks.size(); i++) {
                         Pair<Long, Long> data = (Pair<Long, Long>) msg.obj;
-                        mCallbacks[i].appTransitionStarting(data.first, data.second);
+                        mCallbacks.get(i).appTransitionStarting(data.first, data.second);
                     }
                     break;
                 case MSG_APP_TRANSITION_FINISHED:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].appTransitionFinished();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).appTransitionFinished();
                     }
                     break;
                 case MSG_ASSIST_DISCLOSURE:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].showAssistDisclosure();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).showAssistDisclosure();
                     }
                     break;
                 case MSG_START_ASSIST:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].startAssist((Bundle) msg.obj);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).startAssist((Bundle) msg.obj);
                     }
                     break;
                 case MSG_CAMERA_LAUNCH_GESTURE:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].onCameraLaunchGestureDetected(msg.arg1);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).onCameraLaunchGestureDetected(msg.arg1);
                     }
                     break;
                 case MSG_SHOW_TV_PICTURE_IN_PICTURE_MENU:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].showTvPictureInPictureMenu();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).showTvPictureInPictureMenu();
                     }
                     break;
                 case MSG_ADD_QS_TILE:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].addQsTile((ComponentName) msg.obj);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).addQsTile((ComponentName) msg.obj);
                     }
                     break;
                 case MSG_REMOVE_QS_TILE:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].remQsTile((ComponentName) msg.obj);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).remQsTile((ComponentName) msg.obj);
                     }
                     break;
                 case MSG_CLICK_QS_TILE:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].clickTile((ComponentName) msg.obj);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).clickTile((ComponentName) msg.obj);
                     }
                     break;
                 case MSG_TOGGLE_APP_SPLIT_SCREEN:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].toggleSplitScreen();
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).toggleSplitScreen();
                     }
                     break;
                 case MSG_HANDLE_SYSNAV_KEY:
-                    for (int i = 0; i < mCallbacks.length; i++) {
-                        mCallbacks[i].handleSystemNavigationKey(msg.arg1);
+                    for (int i = 0; i < mCallbacks.size(); i++) {
+                        mCallbacks.get(i).handleSystemNavigationKey(msg.arg1);
                     }
                     break;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 173a110..93c48f8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -74,6 +74,7 @@
     private int mMaxHeadsUpHeight;
     private int mNotificationMinHeight;
     private int mNotificationMaxHeight;
+    private int mNotificationAmbientHeight;
     private int mIncreasedPaddingBetweenElements;
 
     /** Does this row contain layouts that can adapt to row expansion */
@@ -197,6 +198,7 @@
     private float mContentTransformationAmount;
     private boolean mIconsVisible = true;
     private boolean mAboveShelf;
+    private boolean mShowAmbient;
     private boolean mIsLastChild;
     private Runnable mOnDismissRunnable;
 
@@ -326,7 +328,8 @@
                         != com.android.internal.R.id.status_bar_latest_event_content;
         int headsUpheight = headsUpCustom && beforeN ? mMaxHeadsUpHeightLegacy
                 : mMaxHeadsUpHeight;
-        layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight);
+        layout.setHeights(minHeight, headsUpheight, mNotificationMaxHeight,
+                mNotificationAmbientHeight);
     }
 
     public StatusBarNotification getStatusBarNotification() {
@@ -954,6 +957,7 @@
         mNotificationMinHeightLegacy = getFontScaledHeight(R.dimen.notification_min_height_legacy);
         mNotificationMinHeight = getFontScaledHeight(R.dimen.notification_min_height);
         mNotificationMaxHeight = getFontScaledHeight(R.dimen.notification_max_height);
+        mNotificationAmbientHeight = getFontScaledHeight(R.dimen.notification_ambient_height);
         mMaxHeadsUpHeightLegacy = getFontScaledHeight(
                 R.dimen.notification_max_heads_up_height_legacy);
         mMaxHeadsUpHeight = getFontScaledHeight(R.dimen.notification_max_heads_up_height);
@@ -1353,6 +1357,8 @@
             return mGuts.getHeight();
         } else if ((isChildInGroup() && !isGroupExpanded())) {
             return mPrivateLayout.getMinHeight();
+        } else if (mShowAmbient) {
+            return getAmbientHeight();
         } else if (mSensitive && mHideSensitiveForIntrinsicHeight) {
             return getMinHeight();
         } else if (mIsSummaryWithChildren && !mOnKeyguard) {
@@ -1683,6 +1689,13 @@
         return showingLayout.getMinHeight();
     }
 
+    private int getAmbientHeight() {
+        NotificationContentView showingLayout = getShowingLayout();
+        return showingLayout.getAmbientChild() != null
+                ? showingLayout.getAmbientChild().getHeight()
+                : getCollapsedHeight();
+    }
+
     @Override
     public int getCollapsedHeight() {
         if (mIsSummaryWithChildren && !mShowingPublic) {
@@ -1879,6 +1892,13 @@
         return mIsPinned || mHeadsupDisappearRunning || (mIsHeadsUp && mAboveShelf);
     }
 
+    public void setShowAmbient(boolean showAmbient) {
+        if (showAmbient != mShowAmbient) {
+            mShowAmbient = showAmbient;
+            notifyHeightChanged(false /* needsAnimation */);
+        }
+    }
+
     public void setAboveShelf(boolean aboveShelf) {
         mAboveShelf = aboveShelf;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index ad6a5db..b45cde8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -31,6 +31,7 @@
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.HybridNotificationView;
@@ -52,6 +53,7 @@
     private static final int VISIBLE_TYPE_EXPANDED = 1;
     private static final int VISIBLE_TYPE_HEADSUP = 2;
     private static final int VISIBLE_TYPE_SINGLELINE = 3;
+    private static final int VISIBLE_TYPE_AMBIENT = 4;
     public static final int UNDEFINED = -1;
 
     private final Rect mClipBounds = new Rect();
@@ -62,6 +64,7 @@
     private View mExpandedChild;
     private View mHeadsUpChild;
     private HybridNotificationView mSingleLineView;
+    private View mAmbientChild;
 
     private RemoteInputView mExpandedRemoteInput;
     private RemoteInputView mHeadsUpRemoteInput;
@@ -69,6 +72,7 @@
     private NotificationViewWrapper mContractedWrapper;
     private NotificationViewWrapper mExpandedWrapper;
     private NotificationViewWrapper mHeadsUpWrapper;
+    private NotificationViewWrapper mAmbientWrapper;
     private HybridGroupManager mHybridGroupManager;
     private int mClipTopAmount;
     private int mContentHeight;
@@ -81,6 +85,7 @@
     private int mSmallHeight;
     private int mHeadsUpHeight;
     private int mNotificationMaxHeight;
+    private int mNotificationAmbientHeight;
     private StatusBarNotification mStatusBarNotification;
     private NotificationGroupManager mGroupManager;
     private RemoteInputController mRemoteInputController;
@@ -136,10 +141,12 @@
         reset();
     }
 
-    public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
+    public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight,
+            int ambientHeight) {
         mSmallHeight = smallHeight;
         mHeadsUpHeight = headsUpMaxHeight;
         mNotificationMaxHeight = maxHeight;
+        mNotificationAmbientHeight = ambientHeight;
     }
 
     @Override
@@ -215,6 +222,17 @@
                     MeasureSpec.makeMeasureSpec(maxSize, MeasureSpec.AT_MOST));
             maxChildHeight = Math.max(maxChildHeight, mSingleLineView.getMeasuredHeight());
         }
+        if (mAmbientChild != null) {
+            int size = Math.min(maxSize, mNotificationAmbientHeight);
+            ViewGroup.LayoutParams layoutParams = mAmbientChild.getLayoutParams();
+            if (layoutParams.height >= 0) {
+                // An actual height is set
+                size = Math.min(size, layoutParams.height);
+            }
+            mAmbientChild.measure(widthMeasureSpec,
+                    MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST));
+            maxChildHeight = Math.max(maxChildHeight, mAmbientChild.getMeasuredHeight());
+        }
         int ownHeight = Math.min(maxChildHeight, maxSize);
         setMeasuredDimension(width, ownHeight);
     }
@@ -293,10 +311,6 @@
     }
 
     public void reset() {
-        if (mContractedChild != null) {
-            mContractedChild.animate().cancel();
-            removeView(mContractedChild);
-        }
         mPreviousExpandedRemoteInputIntent = null;
         if (mExpandedRemoteInput != null) {
             mExpandedRemoteInput.onNotificationUpdateOrReset();
@@ -327,7 +341,6 @@
             removeView(mHeadsUpChild);
             mHeadsUpRemoteInput = null;
         }
-        mContractedChild = null;
         mExpandedChild = null;
         mHeadsUpChild = null;
     }
@@ -344,6 +357,10 @@
         return mHeadsUpChild;
     }
 
+    public View getAmbientChild() {
+        return mAmbientChild;
+    }
+
     public void setContractedChild(View child) {
         if (mContractedChild != null) {
             mContractedChild.animate().cancel();
@@ -378,6 +395,17 @@
                 mContainingNotification);
     }
 
+    public void setAmbientChild(View child) {
+        if (mAmbientChild != null) {
+            mAmbientChild.animate().cancel();
+            removeView(mAmbientChild);
+        }
+        addView(child);
+        mAmbientChild = child;
+        mAmbientWrapper = NotificationViewWrapper.wrap(getContext(), child,
+                mContainingNotification);
+    }
+
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
@@ -452,6 +480,11 @@
                         com.android.internal.R.dimen.notification_action_list_height);
         }
 
+        if (isVisibleOrTransitioning(VISIBLE_TYPE_AMBIENT)) {
+            return mContractedChild.getHeight() + mContext.getResources().getDimensionPixelSize(
+                    com.android.internal.R.dimen.notification_action_list_height);
+        }
+
         // Transition between heads-up & expanded, or pinned.
         if (mHeadsUpChild != null && mExpandedChild != null) {
             boolean transitioningBetweenHunAndExpanded =
@@ -656,39 +689,26 @@
     }
 
     private void forceUpdateVisibilities() {
-        boolean contractedVisible = mVisibleType == VISIBLE_TYPE_CONTRACTED
-                || mTransformationStartVisibleType == VISIBLE_TYPE_CONTRACTED;
-        boolean expandedVisible = mVisibleType == VISIBLE_TYPE_EXPANDED
-                || mTransformationStartVisibleType == VISIBLE_TYPE_EXPANDED;
-        boolean headsUpVisible = mVisibleType == VISIBLE_TYPE_HEADSUP
-                || mTransformationStartVisibleType == VISIBLE_TYPE_HEADSUP;
-        boolean singleLineVisible = mVisibleType == VISIBLE_TYPE_SINGLELINE
-                || mTransformationStartVisibleType == VISIBLE_TYPE_SINGLELINE;
-        if (!contractedVisible) {
-            mContractedChild.setVisibility(View.INVISIBLE);
+        forceUpdateVisibility(VISIBLE_TYPE_CONTRACTED, mContractedChild, mContractedWrapper);
+        forceUpdateVisibility(VISIBLE_TYPE_EXPANDED, mExpandedChild, mExpandedWrapper);
+        forceUpdateVisibility(VISIBLE_TYPE_HEADSUP, mHeadsUpChild, mHeadsUpWrapper);
+        forceUpdateVisibility(VISIBLE_TYPE_SINGLELINE, mSingleLineView, mSingleLineView);
+        forceUpdateVisibility(VISIBLE_TYPE_AMBIENT, mAmbientChild, mAmbientWrapper);
+        // forceUpdateVisibilities cancels outstanding animations without updating the
+        // mAnimationStartVisibleType. Do so here instead.
+        mAnimationStartVisibleType = UNDEFINED;
+    }
+
+    private void forceUpdateVisibility(int type, View view, TransformableView wrapper) {
+        if (view == null) {
+            return;
+        }
+        boolean visible = mVisibleType == type
+                || mTransformationStartVisibleType == type;
+        if (!visible) {
+            view.setVisibility(INVISIBLE);
         } else {
-            mContractedWrapper.setVisible(true);
-        }
-        if (mExpandedChild != null) {
-            if (!expandedVisible) {
-                mExpandedChild.setVisibility(View.INVISIBLE);
-            } else {
-                mExpandedWrapper.setVisible(true);
-            }
-        }
-        if (mHeadsUpChild != null) {
-            if (!headsUpVisible) {
-                mHeadsUpChild.setVisibility(View.INVISIBLE);
-            } else {
-                mHeadsUpWrapper.setVisible(true);
-            }
-        }
-        if (mSingleLineView != null) {
-            if (!singleLineVisible) {
-                mSingleLineView.setVisibility(View.INVISIBLE);
-            } else {
-                mSingleLineView.setVisible(true);
-            }
+            wrapper.setVisible(true);
         }
     }
 
@@ -722,19 +742,25 @@
     }
 
     private void updateViewVisibilities(int visibleType) {
-        boolean contractedVisible = visibleType == VISIBLE_TYPE_CONTRACTED;
-        mContractedWrapper.setVisible(contractedVisible);
-        if (mExpandedChild != null) {
-            boolean expandedVisible = visibleType == VISIBLE_TYPE_EXPANDED;
-            mExpandedWrapper.setVisible(expandedVisible);
-        }
-        if (mHeadsUpChild != null) {
-            boolean headsUpVisible = visibleType == VISIBLE_TYPE_HEADSUP;
-            mHeadsUpWrapper.setVisible(headsUpVisible);
-        }
-        if (mSingleLineView != null) {
-            boolean singleLineVisible = visibleType == VISIBLE_TYPE_SINGLELINE;
-            mSingleLineView.setVisible(singleLineVisible);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_CONTRACTED,
+                mContractedChild, mContractedWrapper);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_EXPANDED,
+                mExpandedChild, mExpandedWrapper);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_HEADSUP,
+                mHeadsUpChild, mHeadsUpWrapper);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_SINGLELINE,
+                mSingleLineView, mSingleLineView);
+        updateViewVisibility(visibleType, VISIBLE_TYPE_AMBIENT,
+                mAmbientChild, mAmbientWrapper);
+        // updateViewVisibilities cancels outstanding animations without updating the
+        // mAnimationStartVisibleType. Do so here instead.
+        mAnimationStartVisibleType = UNDEFINED;
+    }
+
+    private void updateViewVisibility(int visibleType, int type, View view,
+            TransformableView wrapper) {
+        if (view != null) {
+            wrapper.setVisible(visibleType == type);
         }
     }
 
@@ -784,6 +810,8 @@
                 return mHeadsUpWrapper;
             case VISIBLE_TYPE_SINGLELINE:
                 return mSingleLineView;
+            case VISIBLE_TYPE_AMBIENT:
+                return mAmbientWrapper;
             default:
                 return mContractedWrapper;
         }
@@ -801,6 +829,8 @@
                 return mHeadsUpChild;
             case VISIBLE_TYPE_SINGLELINE:
                 return mSingleLineView;
+            case VISIBLE_TYPE_AMBIENT:
+                return mAmbientChild;
             default:
                 return mContractedChild;
         }
@@ -814,6 +844,8 @@
                 return mHeadsUpWrapper;
             case VISIBLE_TYPE_CONTRACTED:
                 return mContractedWrapper;
+            case VISIBLE_TYPE_AMBIENT:
+                return mAmbientWrapper;
             default:
                 return null;
         }
@@ -823,6 +855,10 @@
      * @return one of the static enum types in this view, calculated form the current state
      */
     public int calculateVisibleType() {
+        if (mDark && !mIsChildInGroup) {
+            // TODO: Handle notification groups
+            return VISIBLE_TYPE_AMBIENT;
+        }
         if (mUserExpanding) {
             int height = !mIsChildInGroup || isGroupExpanded()
                     || mContainingNotification.isExpanded(true /* allowOnKeyguard */)
@@ -895,6 +931,7 @@
         if (mSingleLineView != null && (mVisibleType == VISIBLE_TYPE_SINGLELINE || !dark)) {
             mSingleLineView.setDark(dark, fade, delay);
         }
+        selectLayout(!dark && fade /* animate */, false /* force */);
     }
 
     public void setHeadsUp(boolean headsUp) {
@@ -947,6 +984,9 @@
         if (mHeadsUpChild != null) {
             mHeadsUpWrapper.notifyContentUpdated(entry.notification);
         }
+        if (mAmbientChild != null) {
+            mAmbientWrapper.notifyContentUpdated(entry.notification);
+        }
         updateShowingLegacyBackground();
         mForceSelectNextLayout = true;
         setDark(mDark, false /* animate */, 0 /* delay */);
@@ -1133,6 +1173,9 @@
         if (header == null && mHeadsUpChild != null) {
             header = mHeadsUpWrapper.getNotificationHeader();
         }
+        if (header == null && mAmbientChild != null) {
+            header = mAmbientWrapper.getNotificationHeader();
+        }
         return header;
     }
 
@@ -1200,6 +1243,11 @@
         }
     }
 
+    @VisibleForTesting
+    boolean isAnimatingVisibleType() {
+        return mAnimationStartVisibleType != UNDEFINED;
+    }
+
     public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
         mHeadsUpAnimatingAway = headsUpAnimatingAway;
         selectLayout(false /* animate */, true /* force */);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index a6e730d..458daf1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -67,6 +67,7 @@
         public RemoteViews cachedBigContentView;
         public RemoteViews cachedHeadsUpContentView;
         public RemoteViews cachedPublicContentView;
+        public RemoteViews cachedAmbientContentView;
         public CharSequence remoteInputText;
         private int mCachedContrastColor = COLOR_INVALID;
         private int mCachedContrastColorIsFor = COLOR_INVALID;
@@ -126,6 +127,8 @@
                         updatedNotificationBuilder.createHeadsUpContentView();
                 final RemoteViews newPublicNotification
                         = updatedNotificationBuilder.makePublicContentView();
+                final RemoteViews newAmbientNotification
+                        = updatedNotificationBuilder.makeAmbientNotification();
 
                 boolean sameCustomView = Objects.equals(
                         notification.getNotification().extras.getBoolean(
@@ -136,11 +139,13 @@
                         && compareRemoteViews(cachedBigContentView, newBigContentView)
                         && compareRemoteViews(cachedHeadsUpContentView, newHeadsUpContentView)
                         && compareRemoteViews(cachedPublicContentView, newPublicNotification)
+                        && compareRemoteViews(cachedAmbientContentView, newAmbientNotification)
                         && sameCustomView;
                 cachedPublicContentView = newPublicNotification;
                 cachedHeadsUpContentView = newHeadsUpContentView;
                 cachedBigContentView = newBigContentView;
                 cachedContentView = newContentView;
+                cachedAmbientContentView = newAmbientNotification;
             } else {
                 final Notification.Builder builder
                         = Notification.Builder.recoverBuilder(ctx, notification.getNotification());
@@ -149,6 +154,7 @@
                 cachedBigContentView = builder.createBigContentView();
                 cachedHeadsUpContentView = builder.createHeadsUpContentView();
                 cachedPublicContentView = builder.makePublicContentView();
+                cachedAmbientContentView = builder.makeAmbientNotification();
 
                 applyInPlace = false;
             }
@@ -488,20 +494,6 @@
         return false;
     }
 
-    /**
-     * Return whether there are any clearable notifications (that aren't errors).
-     */
-    public boolean hasActiveClearableNotifications() {
-        for (Entry e : mSortedAndFiltered) {
-            if (e.getContentView() != null) { // the view successfully inflated
-                if (e.notification.isClearable()) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
     // Q: What kinds of notifications should show during setup?
     // A: Almost none! Only things coming from the system (package is "android") that also
     // have special "kind" tags marking them as relevant for setup (see below).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index bc1b9fb..e8e9d4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -67,6 +67,7 @@
     private int mStatusBarState;
     private float mMaxShelfEnd;
     private int mRelativeOffset;
+    private boolean mInteractive;
 
     public NotificationShelf(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -128,6 +129,7 @@
         } else {
             mViewInvertHelper.update(dark);
         }
+        mShelfIcons.setAmbient(dark);
     }
 
     @Override
@@ -555,13 +557,18 @@
     }
 
     private void updateInteractiveness() {
-        boolean interactive = mStatusBarState == StatusBarState.KEYGUARD && mHasItemsInStableShelf;
-        setClickable(interactive);
-        setFocusable(interactive);
-        setImportantForAccessibility(interactive ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
+        mInteractive = mStatusBarState == StatusBarState.KEYGUARD && mHasItemsInStableShelf;
+        setClickable(mInteractive);
+        setFocusable(mInteractive);
+        setImportantForAccessibility(mInteractive ? View.IMPORTANT_FOR_ACCESSIBILITY_YES
                 : View.IMPORTANT_FOR_ACCESSIBILITY_NO);
     }
 
+    @Override
+    protected boolean isInteractive() {
+        return mInteractive;
+    }
+
     public void setMaxShelfEnd(float maxShelfEnd) {
         mMaxShelfEnd = maxShelfEnd;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index a2c2fd7..399b0d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -221,6 +221,8 @@
         setContentDescription(icon.contentDescription);
         if (!iconEquals) {
             if (!updateDrawable(false /* no clear */)) return false;
+            // we have to clear the grayscale tag since it may have changed
+            setTag(R.id.icon_is_grayscale, null);
         }
         if (!levelEquals) {
             setImageLevel(icon.iconLevel);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index dd5832b..7adb36d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -64,6 +64,7 @@
 
     private ConnectedDeviceSignalController mConnectedDeviceSignalController;
     private View mSignalsView;
+    private CarNavigationBarView mNavigationBarView;
 
     @Override
     public void start() {
@@ -121,7 +122,17 @@
     }
 
     @Override
-    protected void addNavigationBar() {
+    protected void createNavigationBar() {
+        if (mNavigationBarView != null) {
+            return;
+        }
+
+        mCarNavigationBar =
+                (CarNavigationBarView) View.inflate(mContext, R.layout.car_navigation_bar, null);
+        mController = new CarNavigationBarController(mContext, mCarNavigationBar,
+                this /* ActivityStarter*/);
+        mNavigationBarView = mCarNavigationBar;
+        mCarNavigationBar.getBarTransitions().setAlwaysOpaque(true);
         WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
                 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
@@ -138,19 +149,6 @@
     }
 
     @Override
-    protected void createNavigationBarView(Context context) {
-        if (mNavigationBarView != null) {
-            return;
-        }
-        mCarNavigationBar =
-                (CarNavigationBarView) View.inflate(context, R.layout.car_navigation_bar, null);
-        mController = new CarNavigationBarController(context, mCarNavigationBar,
-                this /* ActivityStarter*/);
-        mNavigationBarView = mCarNavigationBar;
-        mCarNavigationBar.getBarTransitions().setAlwaysOpaque(true);
-    }
-
-    @Override
     public void showBatteryView() {
         if (Log.isLoggable(TAG, Log.DEBUG)) {
             Log.d(TAG, "showBatteryView(). mBatteryMeterView: " + mBatteryMeterView);
@@ -191,12 +189,6 @@
         mContext.registerReceiver(mPackageChangeReceiver, filter);
     }
 
-    @Override
-    protected void repositionNavigationBar() {
-        // The navigation bar for a vehicle will not need to be repositioned, as it is always
-        // set at the bottom.
-    }
-
     public boolean hasDockedTask() {
         return Recents.getSystemServices().hasDockedTask();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 7ca2df9..b984c0b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -116,8 +116,10 @@
 
     private void resolveTemplateViews(StatusBarNotification notification) {
         mPicture = (ImageView) mView.findViewById(com.android.internal.R.id.right_icon);
-        mPicture.setTag(ImageTransformState.ICON_TAG,
-                notification.getNotification().getLargeIcon());
+        if (mPicture != null) {
+            mPicture.setTag(ImageTransformState.ICON_TAG,
+                    notification.getNotification().getLargeIcon());
+        }
         mTitle = (TextView) mView.findViewById(com.android.internal.R.id.title);
         mText = (TextView) mView.findViewById(com.android.internal.R.id.text);
         final View progress = mView.findViewById(com.android.internal.R.id.progress);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
index 5047041..a4e5916 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/VisualStabilityManager.java
@@ -39,6 +39,7 @@
     private VisibilityLocationProvider mVisibilityLocationProvider;
     private ArraySet<View> mAllowedReorderViews = new ArraySet<>();
     private ArraySet<View> mAddedChildren = new ArraySet<>();
+    private boolean mPulsing;
 
     /**
      * Add a callback to invoke when reordering is allowed again.
@@ -67,8 +68,16 @@
         updateReorderingAllowed();
     }
 
+    /**
+     * @param pulsing whether we are currently pulsing for ambient display.
+     */
+    public void setPulsing(boolean pulsing) {
+        mPulsing = pulsing;
+        updateReorderingAllowed();
+    }
+
     private void updateReorderingAllowed() {
-        boolean reorderingAllowed = !mScreenOn || !mPanelExpanded;
+        boolean reorderingAllowed = (!mScreenOn || !mPanelExpanded) && !mPulsing;
         boolean changed = reorderingAllowed && !mReorderingAllowed;
         mReorderingAllowed = reorderingAllowed;
         if (changed) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 01ffe01..b78f748 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -26,6 +26,7 @@
 import android.view.View;
 import android.view.animation.Interpolator;
 
+import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.Interpolators;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
@@ -41,7 +42,9 @@
     private final Handler mHandler = new Handler();
     private final ScrimController mScrimController;
 
+    private final Context mContext;
     private final View mStackScroller;
+    private final NotificationPanelView mNotificationPanelView;
 
     private boolean mDozing;
     private DozeHost.PulseCallback mPulseCallback;
@@ -52,10 +55,12 @@
     private float mBehindTarget;
 
     public DozeScrimController(ScrimController scrimController, Context context,
-            View stackScroller) {
+            View stackScroller, NotificationPanelView notificationPanelView) {
+        mContext = context;
         mStackScroller = stackScroller;
         mScrimController = scrimController;
         mDozeParameters = new DozeParameters(context);
+        mNotificationPanelView = notificationPanelView;
     }
 
     public void setDozing(boolean dozing, boolean animate) {
@@ -65,10 +70,7 @@
             abortAnimations();
             mScrimController.setDozeBehindAlpha(1f);
             mScrimController.setDozeInFrontAlpha(mDozeParameters.getAlwaysOn() ? 0f : 1f);
-            if (mDozeParameters.getAlwaysOn()) {
-                mStackScroller.setAlpha(0f);
-                mHandler.postDelayed(() -> mStackScroller.setAlpha(0f), 30);
-            }
+            mNotificationPanelView.setDark(true);
         } else {
             cancelPulsing();
             if (animate) {
@@ -83,9 +85,8 @@
                 mScrimController.setDozeBehindAlpha(0f);
                 mScrimController.setDozeInFrontAlpha(0f);
             }
-            if (mDozeParameters.getAlwaysOn()) {
-                mStackScroller.setAlpha(1f);
-            }
+            // TODO: animate
+            mNotificationPanelView.setDark(false);
         }
     }
 
@@ -123,9 +124,6 @@
         if (isPulsing()) {
             final boolean pickupOrDoubleTap = mPulseReason == DozeLog.PULSE_REASON_SENSOR_PICKUP
                     || mPulseReason == DozeLog.PULSE_REASON_SENSOR_DOUBLE_TAP;
-            if (mDozeParameters.getAlwaysOn()) {
-                mStackScroller.setAlpha(1f);
-            }
             startScrimAnimation(true /* inFront */, 0f,
                     mDozeParameters.getPulseInDuration(pickupOrDoubleTap),
                     pickupOrDoubleTap ? Interpolators.LINEAR_OUT_SLOW_IN : Interpolators.ALPHA_OUT,
@@ -291,9 +289,6 @@
         @Override
         public void run() {
             if (DEBUG) Log.d(TAG, "Pulse out finished");
-            if (mDozeParameters.getAlwaysOn()) {
-                mStackScroller.setAlpha(0f);
-            }
             DozeLog.tracePulseFinish();
 
             // Signal that the pulse is all finished so we can turn the screen off now.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
index 70beac8ea..c78ec83 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardClockPositionAlgorithm.java
@@ -68,6 +68,8 @@
     }
 
     private AccelerateInterpolator mAccelerateInterpolator = new AccelerateInterpolator();
+    private int mClockBottom;
+    private boolean mDark;
 
     /**
      * Refreshes the dimension values.
@@ -86,7 +88,8 @@
     }
 
     public void setup(int maxKeyguardNotifications, int maxPanelHeight, float expandedHeight,
-            int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount) {
+            int notificationCount, int height, int keyguardStatusHeight, float emptyDragAmount,
+            int clockBottom, boolean dark) {
         mMaxKeyguardNotifications = maxKeyguardNotifications;
         mMaxPanelHeight = maxPanelHeight;
         mExpandedHeight = expandedHeight;
@@ -94,6 +97,8 @@
         mHeight = height;
         mKeyguardStatusHeight = keyguardStatusHeight;
         mEmptyDragAmount = emptyDragAmount;
+        mClockBottom = clockBottom;
+        mDark = dark;
     }
 
     public float getMinStackScrollerPadding(int height, int keyguardStatusHeight) {
@@ -115,6 +120,9 @@
                 result.clockY,
                 y + getClockNotificationsPadding() + mKeyguardStatusHeight);
         result.clockAlpha = getClockAlpha(result.clockScale);
+        if (mDark) {
+            result.stackScrollerPadding = mClockBottom + y;
+        }
     }
 
     private float getClockScale(int notificationPadding, int clockY, int startPadding) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
index b5358a1..26b0d53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarController.java
@@ -34,8 +34,8 @@
     private final StatusBarIconController mStatusBarIconController;
     private final BatteryController mBatteryController;
     private FingerprintUnlockController mFingerprintUnlockController;
-    private final NavigationBarView mNavigationBarView;
 
+    private LightBarTransitionsController mNavigationBarController;
     private int mSystemUiVisibility;
     private int mFullscreenStackVisibility;
     private int mDockedStackVisibility;
@@ -43,29 +43,42 @@
     private boolean mDockedLight;
     private int mLastStatusBarMode;
     private int mLastNavigationBarMode;
+
+    /**
+     * Whether the navigation bar should be light factoring in already how much alpha the scrim has
+     */
     private boolean mNavigationLight;
+
+    /**
+     * Whether the flags indicate that a light status bar is requested. This doesn't factor in the
+     * scrim alpha yet.
+     */
+    private boolean mHasLightNavigationBar;
+    private boolean mScrimAlphaBelowThreshold;
     private float mScrimAlpha;
 
     private final Rect mLastFullscreenBounds = new Rect();
     private final Rect mLastDockedBounds = new Rect();
 
     public LightBarController(StatusBarIconController statusBarIconController,
-            NavigationBarView navigationBarView,
             BatteryController batteryController) {
         mStatusBarIconController = statusBarIconController;
-        mNavigationBarView = navigationBarView;
         mBatteryController = batteryController;
         batteryController.addCallback(this);
     }
 
+    public void setNavigationBar(LightBarTransitionsController navigationBar) {
+        mNavigationBarController = navigationBar;
+    }
+
     public void setFingerprintUnlockController(
             FingerprintUnlockController fingerprintUnlockController) {
         mFingerprintUnlockController = fingerprintUnlockController;
     }
 
-    public void onSystemUiVisibilityChanged(int vis, int fullscreenStackVis, int dockedStackVis,
+    public void onSystemUiVisibilityChanged(int fullscreenStackVis, int dockedStackVis,
             int mask, Rect fullscreenStackBounds, Rect dockedStackBounds, boolean sbModeChanged,
-            int statusBarMode, boolean nbModeChanged, int navigationBarMode) {
+            int statusBarMode) {
         int oldFullscreen = mFullscreenStackVisibility;
         int newFullscreen = (oldFullscreen & ~mask) | (fullscreenStackVis & mask);
         int diffFullscreen = newFullscreen ^ oldFullscreen;
@@ -84,41 +97,47 @@
             updateStatus(fullscreenStackBounds, dockedStackBounds);
         }
 
+        mFullscreenStackVisibility = newFullscreen;
+        mDockedStackVisibility = newDocked;
+        mLastStatusBarMode = statusBarMode;
+        mLastFullscreenBounds.set(fullscreenStackBounds);
+        mLastDockedBounds.set(dockedStackBounds);
+    }
+
+    public void onNavigationVisibilityChanged(int vis, int mask, boolean nbModeChanged,
+            int navigationBarMode) {
         int oldVis = mSystemUiVisibility;
         int newVis = (oldVis & ~mask) | (vis & mask);
         int diffVis = newVis ^ oldVis;
         if ((diffVis & View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR) != 0
                 || nbModeChanged) {
             boolean last = mNavigationLight;
-            mNavigationLight = isNavigationLight(newVis, navigationBarMode);
+            mHasLightNavigationBar = isLight(vis, navigationBarMode,
+                    View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);
+            mNavigationLight = mHasLightNavigationBar && mScrimAlphaBelowThreshold;
             if (mNavigationLight != last) {
                 updateNavigation();
             }
         }
-        mFullscreenStackVisibility = newFullscreen;
-        mDockedStackVisibility = newDocked;
         mSystemUiVisibility = newVis;
-        mLastStatusBarMode = statusBarMode;
         mLastNavigationBarMode = navigationBarMode;
-        mLastFullscreenBounds.set(fullscreenStackBounds);
-        mLastDockedBounds.set(dockedStackBounds);
     }
 
     private void reevaluate() {
-        onSystemUiVisibilityChanged(mSystemUiVisibility, mFullscreenStackVisibility,
+        onSystemUiVisibilityChanged(mFullscreenStackVisibility,
                 mDockedStackVisibility, 0 /* mask */, mLastFullscreenBounds, mLastDockedBounds,
-                true /* sbModeChange*/, mLastStatusBarMode, true /* nbModeChange*/,
+                true /* sbModeChange*/, mLastStatusBarMode);
+        onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */, true /* nbModeChanged */,
                 mLastNavigationBarMode);
     }
 
     public void setScrimAlpha(float alpha) {
         mScrimAlpha = alpha;
-        reevaluate();
-    }
-
-    private boolean isNavigationLight(int vis, int barMode) {
-        return isLight(vis, barMode, View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR)
-                && mScrimAlpha < NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
+        boolean belowThresholdBefore = mScrimAlphaBelowThreshold;
+        mScrimAlphaBelowThreshold = mScrimAlpha < NAV_BAR_INVERSION_SCRIM_ALPHA_THRESHOLD;
+        if (mHasLightNavigationBar && belowThresholdBefore != mScrimAlphaBelowThreshold) {
+            reevaluate();
+        }
     }
 
     private boolean isLight(int vis, int barMode, int flag) {
@@ -169,8 +188,8 @@
     }
 
     private void updateNavigation() {
-        if (mNavigationBarView != null) {
-            mNavigationBarView.getLightTransitionsController().setIconsDark(
+        if (mNavigationBarController != null) {
+            mNavigationBarController.setIconsDark(
                     mNavigationLight, animateChange());
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 1d4d2d1..0f9f056 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import android.animation.ValueAnimator;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.SystemClock;
 
@@ -28,6 +29,7 @@
 public class LightBarTransitionsController {
 
     public static final long DEFAULT_TINT_ANIMATION_DURATION = 120;
+    private static final String EXTRA_DARK_INTENSITY = "dark_intensity";
 
     private final Handler mHandler;
     private final DarkIntensityApplier mApplier;
@@ -40,6 +42,7 @@
     private float mPendingDarkIntensity;
     private ValueAnimator mTintAnimator;
     private float mDarkIntensity;
+    private float mNextDarkIntensity;
 
     private final Runnable mTransitionDeferringDoneRunnable = new Runnable() {
         @Override
@@ -53,6 +56,16 @@
         mHandler = new Handler();
     }
 
+    public void saveState(Bundle outState) {
+        float intensity = mTintAnimator != null && mTintAnimator.isRunning()
+                ?  mNextDarkIntensity : mDarkIntensity;
+        outState.putFloat(EXTRA_DARK_INTENSITY, intensity);
+    }
+
+    public void restoreState(Bundle savedInstanceState) {
+        setIconTintInternal(savedInstanceState.getFloat(EXTRA_DARK_INTENSITY, 0));
+    }
+
     public void appTransitionPending() {
         mTransitionPending = true;
     }
@@ -119,6 +132,7 @@
         if (mDarkIntensity == targetDarkIntensity) {
             return;
         }
+        mNextDarkIntensity = targetDarkIntensity;
         mTintAnimator = ValueAnimator.ofFloat(mDarkIntensity, targetDarkIntensity);
         mTintAnimator.addUpdateListener(
                 animation -> setIconTintInternal((Float) animation.getAnimatedValue()));
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
new file mode 100644
index 0000000..c0f245c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -0,0 +1,666 @@
+/*
+ * 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.phone;
+
+import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
+import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.app.StatusBarManager.windowStateToString;
+
+import static com.android.systemui.statusbar.phone.BarTransitions.MODE_SEMI_TRANSPARENT;
+import static com.android.systemui.statusbar.phone.PhoneStatusBar.DEBUG_WINDOW_STATE;
+import static com.android.systemui.statusbar.phone.PhoneStatusBar.dumpBarTransitions;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityManagerNative;
+import android.app.Fragment;
+import android.app.IActivityManager;
+import android.app.StatusBarManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Configuration;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.inputmethodservice.InputMethodService;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.telecom.TelecomManager;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.IRotationWatcher.Stub;
+import android.view.KeyEvent;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.view.WindowManager.LayoutParams;
+import android.view.WindowManagerGlobal;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.keyguard.LatencyTracker;
+import com.android.systemui.R;
+import com.android.systemui.SystemUIApplication;
+import com.android.systemui.assist.AssistManager;
+import com.android.systemui.fragments.FragmentHostManager;
+import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.CommandQueue.Callbacks;
+import com.android.systemui.statusbar.policy.KeyButtonView;
+import com.android.systemui.statusbar.stack.StackStateAnimator;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.Locale;
+
+/**
+ * Fragment containing the NavigationBarFragment. Contains logic for what happens
+ * on clicks and view states of the nav bar.
+ */
+public class NavigationBarFragment extends Fragment implements Callbacks {
+
+    private static final String TAG = "NavigationBar";
+    private static final boolean DEBUG = false;
+    private static final String EXTRA_DISABLE_STATE = "disabled_state";
+
+    /** Allow some time inbetween the long press for back and recents. */
+    private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
+
+    protected NavigationBarView mNavigationBarView = null;
+    protected AssistManager mAssistManager;
+
+    private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
+
+    private int mNavigationIconHints = 0;
+    private int mNavigationBarMode;
+    protected AccessibilityManager mAccessibilityManager;
+
+    private int mDisabledFlags1;
+    private PhoneStatusBar mPhoneStatusBar;
+    private Recents mRecents;
+    private Divider mDivider;
+    private WindowManager mWindowManager;
+    private CommandQueue mCommandQueue;
+    private long mLastLockToAppLongPress;
+
+    private Locale mLocale;
+    private int mLayoutDirection;
+
+    private int mSystemUiVisibility;
+    private LightBarController mLightBarController;
+    private boolean mKeyguardGoingAway;
+
+    public boolean mHomeBlockedThisTouch;
+
+    // ----- Fragment Lifecycle Callbacks -----
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        mCommandQueue = SystemUIApplication.getComponent(getContext(), CommandQueue.class);
+        mCommandQueue.addCallbacks(this);
+        mPhoneStatusBar = SystemUIApplication.getComponent(getContext(), PhoneStatusBar.class);
+        mRecents = SystemUIApplication.getComponent(getContext(), Recents.class);
+        mDivider = SystemUIApplication.getComponent(getContext(), Divider.class);
+        mWindowManager = getContext().getSystemService(WindowManager.class);
+        mAccessibilityManager = getContext().getSystemService(AccessibilityManager.class);
+        if (savedInstanceState != null) {
+            mDisabledFlags1 = savedInstanceState.getInt(EXTRA_DISABLE_STATE, 0);
+        }
+
+        try {
+            WindowManagerGlobal.getWindowManagerService()
+                    .watchRotation(mRotationWatcher);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        mCommandQueue.removeCallbacks(this);
+        try {
+            WindowManagerGlobal.getWindowManagerService()
+                    .removeRotationWatcher(mRotationWatcher);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+            Bundle savedInstanceState) {
+        return inflater.inflate(R.layout.navigation_bar, container, false);
+    }
+
+    @Override
+    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+        super.onViewCreated(view, savedInstanceState);
+        mNavigationBarView = (NavigationBarView) view;
+
+        mNavigationBarView.setDisabledFlags(mDisabledFlags1);
+        mNavigationBarView.setComponents(mRecents, mDivider);
+        mNavigationBarView.setOnVerticalChangedListener(this::onVerticalChanged);
+        mNavigationBarView.setOnTouchListener(this::onNavigationTouch);
+        if (savedInstanceState != null) {
+            mNavigationBarView.getLightTransitionsController().restoreState(savedInstanceState);
+        }
+
+        prepareNavigationBarView();
+        checkNavBarModes();
+
+        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_OFF);
+        filter.addAction(Intent.ACTION_SCREEN_ON);
+        getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+        PowerManager pm = getContext().getSystemService(PowerManager.class);
+        notifyNavigationBarScreenOn(pm.isScreenOn());
+    }
+
+    @Override
+    public void onDestroyView() {
+        super.onDestroyView();
+        getContext().unregisterReceiver(mBroadcastReceiver);
+    }
+
+    @Override
+    public void onSaveInstanceState(Bundle outState) {
+        super.onSaveInstanceState(outState);
+        outState.putInt(EXTRA_DISABLE_STATE, mDisabledFlags1);
+        if (mNavigationBarView != null) {
+            mNavigationBarView.getLightTransitionsController().saveState(outState);
+        }
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        final Locale locale = getContext().getResources().getConfiguration().locale;
+        final int ld = TextUtils.getLayoutDirectionFromLocale(locale);
+        if (!locale.equals(mLocale) || ld != mLayoutDirection) {
+            if (DEBUG) {
+                Log.v(TAG, String.format(
+                        "config changed locale/LD: %s (%d) -> %s (%d)", mLocale, mLayoutDirection,
+                        locale, ld));
+            }
+            mLocale = locale;
+            mLayoutDirection = ld;
+            refreshLayout(ld);
+        }
+        repositionNavigationBar();
+    }
+
+    @Override
+    public void dump(String prefix, FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mNavigationBarView != null) {
+            pw.print("  mNavigationBarWindowState=");
+            pw.println(windowStateToString(mNavigationBarWindowState));
+            pw.print("  mNavigationBarMode=");
+            pw.println(BarTransitions.modeToString(mNavigationBarMode));
+            dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
+        }
+
+        pw.print("  mNavigationBarView=");
+        if (mNavigationBarView == null) {
+            pw.println("null");
+        } else {
+            mNavigationBarView.dump(fd, pw, args);
+        }
+    }
+
+    // ----- CommandQueue Callbacks -----
+
+    @Override
+    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
+            boolean showImeSwitcher) {
+        boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
+        int hints = mNavigationIconHints;
+        if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
+            hints |= NAVIGATION_HINT_BACK_ALT;
+        } else {
+            hints &= ~NAVIGATION_HINT_BACK_ALT;
+        }
+        if (showImeSwitcher) {
+            hints |= NAVIGATION_HINT_IME_SHOWN;
+        } else {
+            hints &= ~NAVIGATION_HINT_IME_SHOWN;
+        }
+        if (hints == mNavigationIconHints) return;
+
+        mNavigationIconHints = hints;
+
+        if (mNavigationBarView != null) {
+            mNavigationBarView.setNavigationIconHints(hints);
+        }
+        mPhoneStatusBar.checkBarModes();
+    }
+
+    @Override
+    public void topAppWindowChanged(boolean showMenu) {
+        if (mNavigationBarView != null) {
+            mNavigationBarView.setMenuVisibility(showMenu);
+        }
+    }
+
+    @Override
+    public void setWindowState(int window, int state) {
+        if (mNavigationBarView != null
+                && window == StatusBarManager.WINDOW_NAVIGATION_BAR
+                && mNavigationBarWindowState != state) {
+            mNavigationBarWindowState = state;
+            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
+        }
+    }
+
+    @Override
+    public void appTransitionPending() {
+        mNavigationBarView.getLightTransitionsController().appTransitionPending();
+    }
+
+    @Override
+    public void appTransitionCancelled() {
+        mNavigationBarView.getLightTransitionsController().appTransitionCancelled();
+    }
+
+    @Override
+    public void appTransitionStarting(long startTime, long duration) {
+        if (mKeyguardGoingAway) return;
+        doAppTransitionStarting(startTime, duration);
+    }
+
+    /**
+     * Calls appTransitionStarting for the nav bar regardless of whether keyguard is going away.
+     * public so PhoneStatusBar can force this when needed.
+     */
+    public void doAppTransitionStarting(long startTime, long duration) {
+        mNavigationBarView.getLightTransitionsController().appTransitionStarting(startTime,
+                duration);
+    }
+
+    // Injected from PhoneStatusBar at creation.
+    public void setCurrentSysuiVisibility(int systemUiVisibility) {
+        mSystemUiVisibility = systemUiVisibility;
+        mNavigationBarMode = mPhoneStatusBar.computeBarMode(0, mSystemUiVisibility,
+                View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
+                View.NAVIGATION_BAR_TRANSPARENT);
+        checkNavBarModes();
+        mPhoneStatusBar.touchAutoHide();
+        mLightBarController.onNavigationVisibilityChanged(mSystemUiVisibility, 0 /* mask */,
+                true /* nbModeChanged */, mNavigationBarMode);
+    }
+
+    @Override
+    public void setSystemUiVisibility(int vis, int fullscreenStackVis, int dockedStackVis,
+            int mask, Rect fullscreenStackBounds, Rect dockedStackBounds) {
+        final int oldVal = mSystemUiVisibility;
+        final int newVal = (oldVal & ~mask) | (vis & mask);
+        final int diff = newVal ^ oldVal;
+        boolean nbModeChanged = false;
+        if (diff != 0) {
+            mSystemUiVisibility = newVal;
+
+            // update navigation bar mode
+            final int nbMode = getView() == null
+                    ? -1 : mPhoneStatusBar.computeBarMode(oldVal, newVal,
+                    View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
+                    View.NAVIGATION_BAR_TRANSPARENT);
+            nbModeChanged = nbMode != -1;
+            if (nbModeChanged) {
+                if (mNavigationBarMode != nbMode) {
+                    mNavigationBarMode = nbMode;
+                    checkNavBarModes();
+                }
+                mPhoneStatusBar.touchAutoHide();
+            }
+        }
+
+        mLightBarController.onNavigationVisibilityChanged(vis, mask, nbModeChanged,
+                mNavigationBarMode);
+    }
+
+    @Override
+    public void disable(int state1, int state2, boolean animate) {
+        // All navigation bar flags are in state1.
+        int masked = state1 & (StatusBarManager.DISABLE_HOME
+                | StatusBarManager.DISABLE_RECENT
+                | StatusBarManager.DISABLE_BACK
+                | StatusBarManager.DISABLE_SEARCH);
+        if (masked != mDisabledFlags1) {
+            mDisabledFlags1 = masked;
+            if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1);
+        }
+    }
+
+    // ----- Internal stuffz -----
+
+    private void refreshLayout(int layoutDirection) {
+        if (mNavigationBarView != null) {
+            mNavigationBarView.setLayoutDirection(layoutDirection);
+        }
+    }
+
+    private boolean shouldDisableNavbarGestures() {
+        return !mPhoneStatusBar.isDeviceProvisioned()
+                || (mDisabledFlags1 & StatusBarManager.DISABLE_SEARCH) != 0;
+    }
+
+    private void repositionNavigationBar() {
+        if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
+
+        prepareNavigationBarView();
+
+        mWindowManager.updateViewLayout((View) mNavigationBarView.getParent(),
+                ((View) mNavigationBarView.getParent()).getLayoutParams());
+    }
+
+    private void notifyNavigationBarScreenOn(boolean screenOn) {
+        mNavigationBarView.notifyScreenOn(screenOn);
+    }
+
+    private void prepareNavigationBarView() {
+        mNavigationBarView.reorient();
+
+        ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
+        recentsButton.setOnClickListener(this::onRecentsClick);
+        recentsButton.setOnTouchListener(this::onRecentsTouch);
+        recentsButton.setLongClickable(true);
+        recentsButton.setOnLongClickListener(this::onLongPressBackRecents);
+
+        ButtonDispatcher backButton = mNavigationBarView.getBackButton();
+        backButton.setLongClickable(true);
+        backButton.setOnLongClickListener(this::onLongPressBackRecents);
+
+        ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
+        homeButton.setOnTouchListener(this::onHomeTouch);
+        homeButton.setOnLongClickListener(this::onHomeLongClick);
+
+        if (mAssistManager != null) {
+            mAssistManager.onConfigurationChanged();
+        }
+    }
+
+    private boolean onHomeTouch(View v, MotionEvent event) {
+        if (mHomeBlockedThisTouch && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
+            return true;
+        }
+        // If an incoming call is ringing, HOME is totally disabled.
+        // (The user is already on the InCallUI at this point,
+        // and his ONLY options are to answer or reject the call.)
+        switch (event.getAction()) {
+            case MotionEvent.ACTION_DOWN:
+                mHomeBlockedThisTouch = false;
+                TelecomManager telecomManager =
+                        getContext().getSystemService(TelecomManager.class);
+                if (telecomManager != null && telecomManager.isRinging()) {
+                    if (mPhoneStatusBar.isKeyguardShowing()) {
+                        Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " +
+                                "No heads up");
+                        mHomeBlockedThisTouch = true;
+                        return true;
+                    }
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mPhoneStatusBar.awakenDreams();
+                break;
+        }
+        return false;
+    }
+
+    private void onVerticalChanged(boolean isVertical) {
+        if (mAssistManager != null) {
+            // TODO: Clean this up.
+            mAssistManager.onConfigurationChanged();
+        }
+        mPhoneStatusBar.setQsScrimEnabled(!isVertical);
+    }
+
+    private boolean onNavigationTouch(View v, MotionEvent event) {
+        mPhoneStatusBar.checkUserAutohide(v, event);
+        return false;
+    }
+
+    private boolean onHomeLongClick(View v) {
+        if (shouldDisableNavbarGestures()) {
+            return false;
+        }
+        MetricsLogger.action(getContext(), MetricsEvent.ACTION_ASSIST_LONG_PRESS);
+        mAssistManager.startAssist(new Bundle() /* args */);
+        mPhoneStatusBar.awakenDreams();
+        if (mNavigationBarView != null) {
+            mNavigationBarView.abortCurrentGesture();
+        }
+        return true;
+    }
+
+    // additional optimization when we have software system buttons - start loading the recent
+    // tasks on touch down
+    private boolean onRecentsTouch(View v, MotionEvent event) {
+        int action = event.getAction() & MotionEvent.ACTION_MASK;
+        if (action == MotionEvent.ACTION_DOWN) {
+            mCommandQueue.preloadRecentApps();
+        } else if (action == MotionEvent.ACTION_CANCEL) {
+            mCommandQueue.cancelPreloadRecentApps();
+        } else if (action == MotionEvent.ACTION_UP) {
+            if (!v.isPressed()) {
+                mCommandQueue.cancelPreloadRecentApps();
+            }
+        }
+        return false;
+    }
+
+    private void onRecentsClick(View v) {
+        if (LatencyTracker.isEnabled(getContext())) {
+            LatencyTracker.getInstance(getContext()).onActionStart(
+                    LatencyTracker.ACTION_TOGGLE_RECENTS);
+        }
+        mPhoneStatusBar.awakenDreams();
+        mCommandQueue.toggleRecentApps();
+    }
+
+    /**
+     * This handles long-press of both back and recents.  They are
+     * handled together to capture them both being long-pressed
+     * at the same time to exit screen pinning (lock task).
+     *
+     * When accessibility mode is on, only a long-press from recents
+     * is required to exit.
+     *
+     * In all other circumstances we try to pass through long-press events
+     * for Back, so that apps can still use it.  Which can be from two things.
+     * 1) Not currently in screen pinning (lock task).
+     * 2) Back is long-pressed without recents.
+     */
+    private boolean onLongPressBackRecents(View v) {
+        try {
+            boolean sendBackLongPress = false;
+            IActivityManager activityManager = ActivityManagerNative.getDefault();
+            boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
+            boolean inLockTaskMode = activityManager.isInLockTaskMode();
+            if (inLockTaskMode && !touchExplorationEnabled) {
+                long time = System.currentTimeMillis();
+                // If we recently long-pressed the other button then they were
+                // long-pressed 'together'
+                if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
+                    activityManager.stopLockTaskMode();
+                    // When exiting refresh disabled flags.
+                    mNavigationBarView.setDisabledFlags(mDisabledFlags1, true);
+                    return true;
+                } else if ((v.getId() == R.id.back)
+                        && !mNavigationBarView.getRecentsButton().getCurrentView().isPressed()) {
+                    // If we aren't pressing recents right now then they presses
+                    // won't be together, so send the standard long-press action.
+                    sendBackLongPress = true;
+                }
+                mLastLockToAppLongPress = time;
+            } else {
+                // If this is back still need to handle sending the long-press event.
+                if (v.getId() == R.id.back) {
+                    sendBackLongPress = true;
+                } else if (touchExplorationEnabled && inLockTaskMode) {
+                    // When in accessibility mode a long press that is recents (not back)
+                    // should stop lock task.
+                    activityManager.stopLockTaskMode();
+                    // When exiting refresh disabled flags.
+                    mNavigationBarView.setDisabledFlags(mDisabledFlags1, true);
+                    return true;
+                } else if (v.getId() == R.id.recent_apps) {
+                    return onLongPressRecents();
+                }
+            }
+            if (sendBackLongPress) {
+                KeyButtonView keyButtonView = (KeyButtonView) v;
+                keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
+                keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
+                return true;
+            }
+        } catch (RemoteException e) {
+            Log.d(TAG, "Unable to reach activity manager", e);
+        }
+        return false;
+    }
+
+    private boolean onLongPressRecents() {
+        if (mRecents == null || !ActivityManager.supportsMultiWindow()
+                || !mDivider.getView().getSnapAlgorithm()
+                .isSplitScreenFeasible()) {
+            return false;
+        }
+
+        return mPhoneStatusBar.toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
+                MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
+    }
+
+    // ----- Methods that PhoneStatusBar talks to (should be minimized) -----
+
+    public void setAssistManager(AssistManager assistManager) {
+        mAssistManager = assistManager;
+    }
+
+    public void setLightBarController(LightBarController lightBarController) {
+        mLightBarController = lightBarController;
+        mLightBarController.setNavigationBar(mNavigationBarView.getLightTransitionsController());
+    }
+
+    public boolean isSemiTransparent() {
+        return mNavigationBarMode == MODE_SEMI_TRANSPARENT;
+    }
+
+    public void onKeyguardOccludedChanged(boolean keyguardOccluded) {
+        mNavigationBarView.onKeyguardOccludedChanged(keyguardOccluded);
+    }
+
+    public void disableAnimationsDuringHide(long delay) {
+        mNavigationBarView.setLayoutTransitionsEnabled(false);
+        mNavigationBarView.postDelayed(() -> mNavigationBarView.setLayoutTransitionsEnabled(true),
+                delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
+    }
+
+    public void setKeyguardGoingAway(boolean keyguardGoingAway) {
+        mKeyguardGoingAway = keyguardGoingAway;
+    }
+
+    public BarTransitions getBarTransitions() {
+        return mNavigationBarView.getBarTransitions();
+    }
+
+    public void checkNavBarModes() {
+        mPhoneStatusBar.checkBarMode(mNavigationBarMode,
+                mNavigationBarWindowState, mNavigationBarView.getBarTransitions());
+    }
+
+    public void finishBarAnimations() {
+        mNavigationBarView.getBarTransitions().finishAnimations();
+    }
+
+    private final Stub mRotationWatcher = new Stub() {
+        @Override
+        public void onRotationChanged(int rotation) throws RemoteException {
+            // We need this to be scheduled as early as possible to beat the redrawing of
+            // window in response to the orientation change.
+            Handler h = getView().getHandler();
+            Message msg = Message.obtain(h, () -> {
+                if (mNavigationBarView != null
+                        && mNavigationBarView.needsReorient(rotation)) {
+                    repositionNavigationBar();
+                }
+            });
+            msg.setAsynchronous(true);
+            h.sendMessageAtFrontOfQueue(msg);
+        }
+    };
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (Intent.ACTION_SCREEN_OFF.equals(action)) {
+                notifyNavigationBarScreenOn(false);
+            } else if (Intent.ACTION_SCREEN_ON.equals(action)) {
+                notifyNavigationBarScreenOn(true);
+            }
+        }
+    };
+
+    public static View create(Context context, FragmentListener listener) {
+        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
+                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
+                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
+                WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
+                        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                        | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
+                        | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
+                        | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
+                        | WindowManager.LayoutParams.FLAG_SLIPPERY,
+                PixelFormat.TRANSLUCENT);
+        lp.token = new Binder();
+        // this will allow the navbar to run in an overlay on devices that support this
+        if (ActivityManager.isHighEndGfx()) {
+            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        }
+        lp.setTitle("NavigationBar");
+        lp.windowAnimations = 0;
+
+        View navigationBarView = LayoutInflater.from(context).inflate(
+                R.layout.navigation_bar_window, null);
+
+        if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + navigationBarView);
+        if (navigationBarView == null) return null;
+
+        context.getSystemService(WindowManager.class).addView(navigationBarView, lp);
+        FragmentHostManager fragmentHost = FragmentHostManager.get(navigationBarView);
+        NavigationBarFragment fragment = new NavigationBarFragment();
+        fragmentHost.getFragmentManager().beginTransaction()
+                .replace(R.id.navigation_bar_frame, fragment, TAG)
+                .commit();
+        fragmentHost.addTagListener(TAG, listener);
+        return navigationBarView;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index b2b093c..b6feb0e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -70,7 +70,6 @@
 
     protected LayoutInflater mLayoutInflater;
     protected LayoutInflater mLandscapeInflater;
-    private int mDensity;
 
     protected FrameLayout mRot0;
     protected FrameLayout mRot90;
@@ -86,7 +85,6 @@
 
     public NavigationBarInflaterView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mDensity = context.getResources().getConfiguration().densityDpi;
         createInflaters();
         Display display = ((WindowManager)
                 context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
@@ -103,18 +101,6 @@
     }
 
     @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        if (mDensity != newConfig.densityDpi) {
-            mDensity = newConfig.densityDpi;
-            createInflaters();
-            inflateChildren();
-            clearViews();
-            inflateLayout(mCurrentLayout);
-        }
-    }
-
-    @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         inflateChildren();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index d22f421..31c78c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -434,7 +434,6 @@
                         || ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
         final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
                 && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
-        final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
 
         ViewGroup navButtons = (ViewGroup) getCurrentView().findViewById(R.id.nav_buttons);
         if (navButtons != null) {
@@ -495,7 +494,8 @@
     }
 
     private void setUseFadingAnimations(boolean useFadingAnimations) {
-        WindowManager.LayoutParams lp = (WindowManager.LayoutParams) getLayoutParams();
+        WindowManager.LayoutParams lp = (WindowManager.LayoutParams) ((ViewGroup) getParent())
+                .getLayoutParams();
         if (lp != null) {
             boolean old = lp.windowAnimations != 0;
             if (!old && useFadingAnimations) {
@@ -506,7 +506,7 @@
                 return;
             }
             WindowManager wm = (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
-            wm.updateViewLayout(this, lp);
+            wm.updateViewLayout((View) getParent(), lp);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 9fb5980..c25a45c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -22,9 +22,7 @@
 import android.graphics.Color;
 import android.graphics.Paint;
 import android.util.AttributeSet;
-import android.util.Property;
 import android.view.View;
-import android.view.animation.Interpolator;
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -32,7 +30,6 @@
 import com.android.systemui.statusbar.StatusBarIconView;
 import com.android.systemui.statusbar.stack.AnimationFilter;
 import com.android.systemui.statusbar.stack.AnimationProperties;
-import com.android.systemui.statusbar.stack.HeadsUpAppearInterpolator;
 import com.android.systemui.statusbar.stack.ViewState;
 
 import java.util.HashMap;
@@ -98,6 +95,7 @@
     private int mActualLayoutWidth = NO_VALUE;
     private float mActualPaddingEnd = NO_VALUE;
     private float mActualPaddingStart = NO_VALUE;
+    private boolean mCentered;
     private boolean mChangingViewPositions;
     private int mAddAnimationStartIndex = -1;
     private int mCannedAnimationStartIndex = -1;
@@ -105,6 +103,7 @@
     private int mIconSize;
     private float mOpenedAmount = 0.0f;
     private float mVisualOverflowAdaption;
+    private boolean mDisallowNextAnimation;
 
     public NotificationIconContainer(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -165,6 +164,7 @@
         }
         mAddAnimationStartIndex = -1;
         mCannedAnimationStartIndex = -1;
+        mDisallowNextAnimation = false;
     }
 
     @Override
@@ -310,6 +310,15 @@
                 numDots++;
             }
         }
+        if (mCentered && translationX < getLayoutEnd()) {
+            float delta = (getLayoutEnd() - translationX) / 2;
+            for (int i = 0; i < childCount; i++) {
+                View view = getChildAt(i);
+                IconState iconState = mIconStates.get(view);
+                iconState.xTranslation += delta;
+            }
+        }
+
         if (isLayoutRtl()) {
             for (int i = 0; i < childCount; i++) {
                 View view = getChildAt(i);
@@ -379,6 +388,11 @@
         mChangingViewPositions = changingViewPositions;
     }
 
+    public void setAmbient(boolean ambient) {
+        mCentered = ambient;
+        mDisallowNextAnimation = true;
+    }
+
     public IconState getIconState(StatusBarIconView icon) {
         return mIconStates.get(icon);
     }
@@ -469,7 +483,7 @@
                     animate = true;
                 }
                 icon.setVisibleState(visibleState);
-                if (animate) {
+                if (animate && !mDisallowNextAnimation) {
                     animateTo(icon, animationProperties);
                 } else {
                     super.applyToView(view);
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 82a5cc2..3bdd5e5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -211,6 +211,7 @@
     private boolean mOpening;
     private int mIndicationBottomPadding;
     private boolean mIsFullWidth;
+    private boolean mDark;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -289,7 +290,7 @@
             lp.width = panelWidth;
             lp.gravity = panelGravity;
             mQsFrame.setLayoutParams(lp);
-            mQs.getView().post(mUpdateHeader);
+            post(mUpdateHeader);
         }
 
         lp = (FrameLayout.LayoutParams) mNotificationStackScroller.getLayoutParams();
@@ -391,7 +392,9 @@
                     mNotificationStackScroller.getNotGoneChildCount(),
                     getHeight(),
                     mKeyguardStatusView.getHeight(),
-                    mEmptyDragAmount);
+                    mEmptyDragAmount,
+                    mKeyguardStatusView.getClockBottom(),
+                    mDark);
             mClockPositionAlgorithm.run(mClockPositionResult);
             if (animate || mClockAnimator != null) {
                 startClockAnimation(mClockPositionResult.clockY);
@@ -2453,4 +2456,10 @@
             }
         }
     };
+
+    public void setDark(boolean dark) {
+        mDark = dark;
+        mKeyguardStatusView.setDark(dark);
+        positionClockAndNotifications();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index bd5296c..191718e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -17,8 +17,6 @@
 package com.android.systemui.statusbar.phone;
 
 
-import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
-import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
 import static android.app.StatusBarManager.WINDOW_STATE_HIDDEN;
 import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
 import static android.app.StatusBarManager.windowStateToString;
@@ -34,9 +32,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.annotation.NonNull;
 import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
-import android.app.IActivityManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -66,7 +62,6 @@
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
-import android.inputmethodservice.InputMethodService;
 import android.media.AudioAttributes;
 import android.media.MediaMetadata;
 import android.media.session.MediaController;
@@ -75,12 +70,10 @@
 import android.media.session.PlaybackState;
 import android.net.Uri;
 import android.os.AsyncTask;
-import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.IBinder;
-import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.Process;
@@ -95,26 +88,22 @@
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.StatusBarNotification;
-import android.telecom.TelecomManager;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
 import android.util.EventLog;
 import android.util.Log;
 import android.view.Display;
-import android.view.IRotationWatcher;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.ThreadedRenderer;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewGroup.LayoutParams;
 import android.view.ViewParent;
 import android.view.ViewStub;
 import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AccelerateInterpolator;
 import android.view.animation.Interpolator;
 import android.widget.DateTimeView;
@@ -129,7 +118,6 @@
 import com.android.keyguard.KeyguardStatusView;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
-import com.android.keyguard.LatencyTracker;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DemoMode;
@@ -189,7 +177,6 @@
 import com.android.systemui.statusbar.policy.FlashlightControllerImpl;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 import com.android.systemui.statusbar.policy.HotspotControllerImpl;
-import com.android.systemui.statusbar.policy.KeyButtonView;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.LocationControllerImpl;
@@ -205,7 +192,7 @@
 import com.android.systemui.statusbar.policy.ZenModeController;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.stack.NotificationStackScrollLayout.OnChildLocationsChangedListener;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
+
 import com.android.systemui.volume.VolumeComponent;
 
 import java.io.FileDescriptor;
@@ -270,9 +257,6 @@
     public static final int FADE_KEYGUARD_DURATION = 300;
     public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
 
-    /** Allow some time inbetween the long press for back and recents. */
-    private static final int LOCK_TO_APP_GESTURE_TOLERENCE = 200;
-
     /** If true, the system is in the half-boot-to-decryption-screen state.
      * Prudently disable QS and notifications.  */
     private static final boolean ONLY_CORE_APPS;
@@ -395,8 +379,6 @@
 
     boolean mExpandedVisible;
 
-    private int mNavigationBarWindowState = WINDOW_STATE_SHOWING;
-
     // the tracker view
     int mTrackingPosition; // the position of the top of the tracking view.
 
@@ -426,8 +408,6 @@
         : null;
 
     private ScreenPinningRequest mScreenPinningRequest;
-
-    private int mNavigationIconHints = 0;
     private HandlerThread mHandlerThread;
     private HandlerThread mTimeTickThread;
     private Handler mTimeTickHandler;
@@ -486,7 +466,6 @@
     private int mInteractingWindows;
     private boolean mAutohideSuspended;
     private int mStatusBarMode;
-    private int mNavigationBarMode;
     private int mMaxKeyguardNotifications;
 
     private ViewMediatorCallback mKeyguardViewMediatorCallback;
@@ -675,7 +654,6 @@
     private RankingMap mLatestRankingMap;
     private boolean mNoAnimationOnNextBarModeChange;
     private FalsingManager mFalsingManager;
-    private long mLastLockToAppLongPress;
 
     private KeyguardUpdateMonitorCallback mUpdateCallback = new KeyguardUpdateMonitorCallback() {
         @Override
@@ -686,6 +664,9 @@
         }
     };
 
+    private NavigationBarFragment mNavigationBar;
+    private View mNavigationBarView;
+
     @Override
     public void start() {
         mDisplay = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
@@ -710,8 +691,6 @@
         // TODO: use MediaSessionManager.SessionListener to hook us up to future updates
         // in session state
 
-        addNavigationBar();
-
         // Lastly, call to the icon policy to install/update all the icons.
         mIconPolicy = new PhoneStatusBarPolicy(mContext, mIconController, mCastController,
                 mHotspotController, mUserInfoController, mBluetoothController,
@@ -809,7 +788,7 @@
             boolean showNav = mWindowManagerService.hasNavigationBar();
             if (DEBUG) Log.v(TAG, "hasNavigationBar=" + showNav);
             if (showNav) {
-                createNavigationBarView(context);
+                createNavigationBar();
             }
         } catch (RemoteException ex) {
             // no window manager? good luck with that
@@ -874,8 +853,10 @@
             }
         });
 
-        mLightBarController = new LightBarController(mIconController, mNavigationBarView,
-                mBatteryController);
+        mLightBarController = new LightBarController(mIconController, mBatteryController);
+        if (mNavigationBar != null) {
+            mNavigationBar.setLightBarController(mLightBarController);
+        }
 
         ScrimView scrimBehind = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_behind);
         ScrimView scrimInFront = (ScrimView) mStatusBarWindow.findViewById(R.id.scrim_in_front);
@@ -897,7 +878,8 @@
         mHeadsUpManager.addListener(mScrimController);
         mStackScroller.setScrimController(mScrimController);
         mStatusBarView.setScrimController(mScrimController);
-        mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller);
+        mDozeScrimController = new DozeScrimController(mScrimController, context, mStackScroller,
+                mNotificationPanel);
 
         // Other icons
         mLocationController = new LocationControllerImpl(mContext,
@@ -1002,8 +984,9 @@
 
 
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mBroadcastReceiver.onReceive(mContext,
-                new Intent(pm.isScreenOn() ? Intent.ACTION_SCREEN_ON : Intent.ACTION_SCREEN_OFF));
+        if (!pm.isScreenOn()) {
+            mBroadcastReceiver.onReceive(mContext, new Intent(Intent.ACTION_SCREEN_OFF));
+        }
         mGestureWakeLock = pm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                 "GestureWakeLock");
         mVibrator = mContext.getSystemService(Vibrator.class);
@@ -1018,7 +1001,6 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
-        filter.addAction(Intent.ACTION_SCREEN_ON);
         filter.addAction(DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG);
         context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
 
@@ -1051,6 +1033,17 @@
                 .getComponent(PhoneStatusBar.class).getTimeTickHandler();
     }
 
+    protected void createNavigationBar() {
+        mNavigationBarView = NavigationBarFragment.create(mContext, (tag, fragment) -> {
+            mNavigationBar = (NavigationBarFragment) fragment;
+            mNavigationBar.setAssistManager(mAssistManager);
+            if (mLightBarController != null) {
+                mNavigationBar.setLightBarController(mLightBarController);
+            }
+            mNavigationBar.setCurrentSysuiVisibility(mSystemUiVisibility);
+        });
+    }
+
     private void initEmergencyCryptkeeperText() {
         View emergencyViewStub = mStatusBarWindow.findViewById(R.id.emergency_cryptkeeper_text);
         if (mNetworkController.hasEmergencyCryptKeeperText()) {
@@ -1175,33 +1168,6 @@
                 R.layout.super_status_bar, null);
     }
 
-    protected void createNavigationBarView(Context context) {
-        inflateNavigationBarView(context);
-        mNavigationBarView.setDisabledFlags(mDisabled1);
-        mNavigationBarView.setComponents(mRecents, getComponent(Divider.class));
-        mNavigationBarView.setOnVerticalChangedListener(
-                new NavigationBarView.OnVerticalChangedListener() {
-            @Override
-            public void onVerticalChanged(boolean isVertical) {
-                if (mAssistManager != null) {
-                    mAssistManager.onConfigurationChanged();
-                }
-                mNotificationPanel.setQsScrimEnabled(!isVertical);
-            }
-        });
-        mNavigationBarView.setOnTouchListener(new View.OnTouchListener() {
-            @Override
-            public boolean onTouch(View v, MotionEvent event) {
-                checkUserAutohide(v, event);
-                return false;
-            }});
-    }
-
-    protected void inflateNavigationBarView(Context context) {
-        mNavigationBarView = (NavigationBarView) View.inflate(
-                context, R.layout.navigation_bar, null);
-    }
-
     protected void initSignalCluster(View containerView) {
         SignalClusterView signalCluster =
                 (SignalClusterView) containerView.findViewById(R.id.signal_cluster);
@@ -1229,8 +1195,10 @@
                 List<ExpandableNotificationRow> children = row.getNotificationChildren();
                 if (row.areChildrenExpanded() && children != null) {
                     for (ExpandableNotificationRow childRow : children) {
-                        if (childRow.getVisibility() == View.VISIBLE) {
-                            viewsToHide.add(childRow);
+                        if (mStackScroller.canChildBeDismissed(childRow)) {
+                            if (childRow.getVisibility() == View.VISIBLE) {
+                                viewsToHide.add(childRow);
+                            }
                         }
                     }
                 }
@@ -1353,18 +1321,6 @@
         return mNaturalBarHeight;
     }
 
-    private View.OnClickListener mRecentsClickListener = new View.OnClickListener() {
-        @Override
-        public void onClick(View v) {
-            if (LatencyTracker.isEnabled(mContext)) {
-                LatencyTracker.getInstance(mContext).onActionStart(
-                        LatencyTracker.ACTION_TOGGLE_RECENTS);
-            }
-            awakenDreams();
-            toggleRecentApps();
-        }
-    };
-
     @Override
     protected boolean toggleSplitScreenMode(int metricsDockAction, int metricsUndockAction) {
         if (mRecents == null) {
@@ -1389,57 +1345,7 @@
         return true;
     }
 
-    private final View.OnLongClickListener mLongPressHomeListener
-            = new View.OnLongClickListener() {
-        @Override
-        public boolean onLongClick(View v) {
-            if (shouldDisableNavbarGestures()) {
-                return false;
-            }
-            MetricsLogger.action(mContext, MetricsEvent.ACTION_ASSIST_LONG_PRESS);
-            mAssistManager.startAssist(new Bundle() /* args */);
-            awakenDreams();
-            if (mNavigationBarView != null) {
-                mNavigationBarView.abortCurrentGesture();
-            }
-            return true;
-        }
-    };
-
-    private final View.OnTouchListener mHomeActionListener = new View.OnTouchListener() {
-        public boolean mBlockedThisTouch;
-
-        @Override
-        public boolean onTouch(View v, MotionEvent event) {
-            if (mBlockedThisTouch && event.getActionMasked() != MotionEvent.ACTION_DOWN) {
-                return true;
-            }
-            // If an incoming call is ringing, HOME is totally disabled.
-            // (The user is already on the InCallUI at this point,
-            // and his ONLY options are to answer or reject the call.)
-            switch (event.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    mBlockedThisTouch = false;
-                    TelecomManager telecomManager = mContext.getSystemService(TelecomManager.class);
-                    if (telecomManager != null && telecomManager.isRinging()) {
-                        if (mStatusBarKeyguardViewManager.isShowing()) {
-                            Log.i(TAG, "Ignoring HOME; there's a ringing incoming call. " +
-                                    "No heads up");
-                            mBlockedThisTouch = true;
-                            return true;
-                        }
-                    }
-                    break;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    awakenDreams();
-                    break;
-            }
-            return false;
-        }
-    };
-
-    private void awakenDreams() {
+    void awakenDreams() {
         if (mDreamManager != null) {
             try {
                 mDreamManager.awaken();
@@ -1449,93 +1355,6 @@
         }
     }
 
-    private void prepareNavigationBarView() {
-        mNavigationBarView.reorient();
-
-        ButtonDispatcher recentsButton = mNavigationBarView.getRecentsButton();
-        recentsButton.setOnClickListener(mRecentsClickListener);
-        recentsButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
-        recentsButton.setLongClickable(true);
-        recentsButton.setOnLongClickListener(this::handleLongPressBackRecents);
-
-        ButtonDispatcher backButton = mNavigationBarView.getBackButton();
-        backButton.setLongClickable(true);
-        backButton.setOnLongClickListener(this::handleLongPressBackRecents);
-
-        ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
-        homeButton.setOnTouchListener(mHomeActionListener);
-        homeButton.setOnLongClickListener(mLongPressHomeListener);
-
-        mAssistManager.onConfigurationChanged();
-    }
-
-    // For small-screen devices (read: phones) that lack hardware navigation buttons
-    protected void addNavigationBar() {
-        if (DEBUG) Log.v(TAG, "addNavigationBar: about to add " + mNavigationBarView);
-        if (mNavigationBarView == null) return;
-
-        try {
-            WindowManagerGlobal.getWindowManagerService()
-                    .watchRotation(new IRotationWatcher.Stub() {
-                @Override
-                public void onRotationChanged(int rotation) throws RemoteException {
-                    // We need this to be scheduled as early as possible to beat the redrawing of
-                    // window in response to the orientation change.
-                    Message msg = Message.obtain(mHandler, () -> {
-                        if (mNavigationBarView != null
-                                && mNavigationBarView.needsReorient(rotation)) {
-                            repositionNavigationBar();
-                        }
-                    });
-                    msg.setAsynchronous(true);
-                    mHandler.sendMessageAtFrontOfQueue(msg);
-                }
-            });
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-
-        prepareNavigationBarView();
-
-        mWindowManager.addView(mNavigationBarView, getNavigationBarLayoutParams());
-    }
-
-    protected void repositionNavigationBar() {
-        if (mNavigationBarView == null || !mNavigationBarView.isAttachedToWindow()) return;
-
-        prepareNavigationBarView();
-
-        mWindowManager.updateViewLayout(mNavigationBarView, mNavigationBarView.getLayoutParams());
-    }
-
-    private void notifyNavigationBarScreenOn(boolean screenOn) {
-        if (mNavigationBarView == null) return;
-        mNavigationBarView.notifyScreenOn(screenOn);
-    }
-
-    private WindowManager.LayoutParams getNavigationBarLayoutParams() {
-        WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT,
-                WindowManager.LayoutParams.TYPE_NAVIGATION_BAR,
-                    0
-                    | WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING
-                    | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
-                    | WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH
-                    | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
-                    | WindowManager.LayoutParams.FLAG_SLIPPERY,
-                PixelFormat.TRANSLUCENT);
-        lp.token = new Binder();
-        // this will allow the navbar to run in an overlay on devices that support this
-        if (ActivityManager.isHighEndGfx()) {
-            lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
-        }
-
-        lp.setTitle("NavigationBar");
-        lp.windowAnimations = 0;
-        return lp;
-    }
-
     @Override
     public void setIcon(String slot, StatusBarIcon icon) {
         mIconController.setIcon(slot, icon);
@@ -1727,8 +1546,15 @@
             }
             List<ExpandableNotificationRow> notificationChildren =
                     entry.row.getNotificationChildren();
-            ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>(notificationChildren);
-            for (int i = 0; i < toRemove.size(); i++) {
+            ArrayList<ExpandableNotificationRow> toRemove = new ArrayList<>();
+            for (int i = 0; i < notificationChildren.size(); i++) {
+                ExpandableNotificationRow row = notificationChildren.get(i);
+                if ((row.getStatusBarNotification().getNotification().flags
+                        & Notification.FLAG_FOREGROUND_SERVICE) != 0) {
+                    // the child is a forground service notification which we can't remove!
+                    continue;
+                }
+                toRemove.add(row);
                 toRemove.get(i).setKeepInParent(true);
                 // we need to set this state earlier as otherwise we might generate some weird
                 // animations
@@ -1752,13 +1578,6 @@
         super.performRemoveNotification(n);
     }
 
-    @Override
-    protected void refreshLayout(int layoutDirection) {
-        if (mNavigationBarView != null) {
-            mNavigationBarView.setLayoutDirection(layoutDirection);
-        }
-    }
-
     private void updateNotificationShade() {
         if (mStackScroller == null) return;
 
@@ -2007,10 +1826,27 @@
     private void updateClearAll() {
         boolean showDismissView =
                 mState != StatusBarState.KEYGUARD &&
-                mNotificationData.hasActiveClearableNotifications();
+               hasActiveClearableNotifications();
         mStackScroller.updateDismissView(showDismissView);
     }
 
+    /**
+     * Return whether there are any clearable notifications
+     */
+    private boolean hasActiveClearableNotifications() {
+        int childCount = mStackScroller.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            View child = mStackScroller.getChildAt(i);
+            if (!(child instanceof ExpandableNotificationRow)) {
+                continue;
+            }
+            if (((ExpandableNotificationRow) child).canViewBeDismissed()) {
+                    return true;
+            }
+        }
+        return false;
+    }
+
     private void updateEmptyShadeView() {
         boolean showEmptyShade =
                 mState != StatusBarState.KEYGUARD &&
@@ -2057,7 +1893,7 @@
 
         if (SPEW) {
             final boolean clearable = hasActiveNotifications() &&
-                    mNotificationData.hasActiveClearableNotifications();
+                    hasActiveClearableNotifications();
             Log.d(TAG, "setAreThereNotifications: N=" +
                     mNotificationData.getActiveNotifications().size() + " any=" +
                     hasActiveNotifications() + " clearable=" + clearable);
@@ -2496,9 +2332,6 @@
                         | StatusBarManager.DISABLE_RECENT
                         | StatusBarManager.DISABLE_BACK
                         | StatusBarManager.DISABLE_SEARCH)) != 0) {
-            // the nav bar will take care of these
-            if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state1);
-
             if ((state1 & StatusBarManager.DISABLE_RECENT) != 0) {
                 // close recents if it's visible
                 mHandler.removeMessages(MSG_HIDE_RECENT_APPS);
@@ -2560,10 +2393,6 @@
         return mLeaveOpenOnKeyguardHide;
     }
 
-    public boolean isQsExpanded() {
-        return mNotificationPanel.isQsExpanded();
-    }
-
     public boolean isWakeUpComingFromTouch() {
         return mWakeUpComingFromTouch;
     }
@@ -2572,6 +2401,7 @@
         return getBarState() == StatusBarState.KEYGUARD;
     }
 
+    @Override
     public boolean isDozing() {
         return mDozing;
     }
@@ -2658,6 +2488,9 @@
             }
         } else {
             updateNotificationRanking(null);
+            if (isHeadsUp) {
+                mDozeServiceHost.fireNotificationHeadsUp();
+            }
         }
 
     }
@@ -3040,17 +2873,6 @@
         return mFingerprintUnlockController;
     }
 
-    private void setNavigationIconHints(int hints) {
-        if (hints == mNavigationIconHints) return;
-
-        mNavigationIconHints = hints;
-
-        if (mNavigationBarView != null) {
-            mNavigationBarView.setNavigationIconHints(hints);
-        }
-        checkBarModes();
-    }
-
     @Override // CommandQueue
     public void setWindowState(int window, int state) {
         boolean showing = state == WINDOW_STATE_SHOWING;
@@ -3064,19 +2886,10 @@
                         1.0f /* speedUpFactor */);
             }
         }
-        if (mNavigationBarView != null
-                && window == StatusBarManager.WINDOW_NAVIGATION_BAR
-                && mNavigationBarWindowState != state) {
-            mNavigationBarWindowState = state;
-            if (DEBUG_WINDOW_STATE) Log.d(TAG, "Navigation bar " + windowStateToString(state));
-        }
     }
 
     @Override // CommandQueue
     public void buzzBeepBlinked() {
-        if (mDozeServiceHost != null) {
-            mDozeServiceHost.fireBuzzBeepBlinked();
-        }
     }
 
     @Override
@@ -3105,7 +2918,6 @@
                 Integer.toHexString(oldVal), Integer.toHexString(newVal),
                 Integer.toHexString(diff)));
         boolean sbModeChanged = false;
-        boolean nbModeChanged = false;
         if (diff != 0) {
             mSystemUiVisibility = newVal;
 
@@ -3123,32 +2935,13 @@
             // update status bar mode
             final int sbMode = computeStatusBarMode(oldVal, newVal);
 
-            // update navigation bar mode
-            final int nbMode = mNavigationBarView == null ? -1 : computeBarMode(
-                    oldVal, newVal, mNavigationBarView.getBarTransitions(),
-                    View.NAVIGATION_BAR_TRANSIENT, View.NAVIGATION_BAR_TRANSLUCENT,
-                    View.NAVIGATION_BAR_TRANSPARENT);
             sbModeChanged = sbMode != -1;
-            nbModeChanged = nbMode != -1;
-            boolean checkBarModes = false;
             if (sbModeChanged && sbMode != mStatusBarMode) {
-                mStatusBarMode = sbMode;
-                checkBarModes = true;
-            }
-            if (nbModeChanged && nbMode != mNavigationBarMode) {
-                mNavigationBarMode = nbMode;
-                checkBarModes = true;
-            }
-            if (checkBarModes) {
-                checkBarModes();
-            }
-            if (sbModeChanged || nbModeChanged) {
-                // update transient bar autohide
-                if (mStatusBarMode == MODE_SEMI_TRANSPARENT || mNavigationBarMode == MODE_SEMI_TRANSPARENT) {
-                    scheduleAutohide();
-                } else {
-                    cancelAutohide();
+                if (sbMode != mStatusBarMode) {
+                    mStatusBarMode = sbMode;
+                    checkBarModes();
                 }
+                touchAutoHide();
             }
 
             if ((vis & View.NAVIGATION_BAR_UNHIDE) != 0) {
@@ -3159,22 +2952,30 @@
             notifyUiVisibilityChanged(mSystemUiVisibility);
         }
 
-        mLightBarController.onSystemUiVisibilityChanged(vis, fullscreenStackVis, dockedStackVis,
-                mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode,
-                nbModeChanged, mNavigationBarMode);
+        mLightBarController.onSystemUiVisibilityChanged(fullscreenStackVis, dockedStackVis,
+                mask, fullscreenStackBounds, dockedStackBounds, sbModeChanged, mStatusBarMode);
+    }
+
+    void touchAutoHide() {
+        // update transient bar autohide
+        if (mStatusBarMode == MODE_SEMI_TRANSPARENT || (mNavigationBar != null
+                && mNavigationBar.isSemiTransparent())) {
+            scheduleAutohide();
+        } else {
+            cancelAutohide();
+        }
     }
 
     protected int computeStatusBarMode(int oldVal, int newVal) {
-        return computeBarMode(oldVal, newVal, getStatusBarTransitions(),
-                View.STATUS_BAR_TRANSIENT, View.STATUS_BAR_TRANSLUCENT,
-                View.STATUS_BAR_TRANSPARENT);
+        return computeBarMode(oldVal, newVal, View.STATUS_BAR_TRANSIENT,
+                View.STATUS_BAR_TRANSLUCENT, View.STATUS_BAR_TRANSPARENT);
     }
 
     protected BarTransitions getStatusBarTransitions() {
         return mStatusBarView.getBarTransitions();
     }
 
-    protected int computeBarMode(int oldVis, int newVis, BarTransitions transitions,
+    protected int computeBarMode(int oldVis, int newVis,
             int transientFlag, int translucentFlag, int transparentFlag) {
         final int oldMode = barMode(oldVis, transientFlag, translucentFlag, transparentFlag);
         final int newMode = barMode(newVis, transientFlag, translucentFlag, transparentFlag);
@@ -3194,22 +2995,21 @@
                 : MODE_OPAQUE;
     }
 
-    private void checkBarModes() {
+    void checkBarModes() {
         if (mDemoMode) return;
-        checkBarMode(mStatusBarMode, mStatusBarWindowState, getStatusBarTransitions(),
-                mNoAnimationOnNextBarModeChange);
-        if (mNavigationBarView != null) {
-            checkBarMode(mNavigationBarMode,
-                    mNavigationBarWindowState, mNavigationBarView.getBarTransitions(),
-                    mNoAnimationOnNextBarModeChange);
-        }
+        checkBarMode(mStatusBarMode, mStatusBarWindowState, getStatusBarTransitions());
+        if (mNavigationBar != null) mNavigationBar.checkNavBarModes();
         mNoAnimationOnNextBarModeChange = false;
     }
 
-    private void checkBarMode(int mode, int windowState, BarTransitions transitions,
-            boolean noAnimation) {
+    // Called by NavigationBarFragment
+    void setQsScrimEnabled(boolean scrimEnabled) {
+        mNotificationPanel.setQsScrimEnabled(scrimEnabled);
+    }
+
+    void checkBarMode(int mode, int windowState, BarTransitions transitions) {
         final boolean powerSave = mBatteryController.isPowerSave();
-        final boolean anim = !noAnimation && mDeviceInteractive
+        final boolean anim = !mNoAnimationOnNextBarModeChange && mDeviceInteractive
                 && windowState != WINDOW_STATE_HIDDEN && !powerSave;
         if (powerSave && getBarState() == StatusBarState.SHADE) {
             mode = MODE_WARNING;
@@ -3219,8 +3019,8 @@
 
     private void finishBarAnimations() {
         mStatusBarView.getBarTransitions().finishAnimations();
-        if (mNavigationBarView != null) {
-            mNavigationBarView.getBarTransitions().finishAnimations();
+        if (mNavigationBar != null) {
+            mNavigationBar.finishBarAnimations();
         }
     }
 
@@ -3278,7 +3078,7 @@
         mHandler.postDelayed(mAutohide, AUTOHIDE_TIMEOUT_MS);
     }
 
-    private void checkUserAutohide(View v, MotionEvent event) {
+    void checkUserAutohide(View v, MotionEvent event) {
         if ((mSystemUiVisibility & STATUS_OR_NAV_TRANSIENT) != 0  // a transient bar is revealed
                 && event.getAction() == MotionEvent.ACTION_OUTSIDE // touch outside the source bar
                 && event.getX() == 0 && event.getY() == 0  // a touch outside both bars
@@ -3331,33 +3131,11 @@
         if (SPEW) {
             Log.d(TAG, (showMenu?"showing":"hiding") + " the MENU button");
         }
-        if (mNavigationBarView != null) {
-            mNavigationBarView.setMenuVisibility(showMenu);
-        }
 
         // See above re: lights-out policy for legacy apps.
         if (showMenu) setLightsOn(true);
     }
 
-    @Override
-    public void setImeWindowStatus(IBinder token, int vis, int backDisposition,
-            boolean showImeSwitcher) {
-        boolean imeShown = (vis & InputMethodService.IME_VISIBLE) != 0;
-        int flags = mNavigationIconHints;
-        if ((backDisposition == InputMethodService.BACK_DISPOSITION_WILL_DISMISS) || imeShown) {
-            flags |= NAVIGATION_HINT_BACK_ALT;
-        } else {
-            flags &= ~NAVIGATION_HINT_BACK_ALT;
-        }
-        if (showImeSwitcher) {
-            flags |= NAVIGATION_HINT_IME_SHOWN;
-        } else {
-            flags &= ~NAVIGATION_HINT_IME_SHOWN;
-        }
-
-        setNavigationIconHints(flags);
-    }
-
     public static String viewInfo(View v) {
         return "[(" + v.getLeft() + "," + v.getTop() + ")(" + v.getRight() + "," + v.getBottom()
                 + ") " + v.getWidth() + "x" + v.getHeight() + "]";
@@ -3388,20 +3166,6 @@
         pw.print("  mUseHeadsUp=");
         pw.println(mUseHeadsUp);
         dumpBarTransitions(pw, "mStatusBarView", mStatusBarView.getBarTransitions());
-        if (mNavigationBarView != null) {
-            pw.print("  mNavigationBarWindowState=");
-            pw.println(windowStateToString(mNavigationBarWindowState));
-            pw.print("  mNavigationBarMode=");
-            pw.println(BarTransitions.modeToString(mNavigationBarMode));
-            dumpBarTransitions(pw, "mNavigationBarView", mNavigationBarView.getBarTransitions());
-        }
-
-        pw.print("  mNavigationBarView=");
-        if (mNavigationBarView == null) {
-            pw.println("null");
-        } else {
-            mNavigationBarView.dump(fd, pw, args);
-        }
 
         pw.print("  mMediaSessionManager=");
         pw.println(mMediaSessionManager);
@@ -3510,7 +3274,7 @@
         }
     }
 
-    private static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
+    static void dumpBarTransitions(PrintWriter pw, String var, BarTransitions transitions) {
         pw.print("  "); pw.print(var); pw.print(".BarTransitions.mMode=");
         pw.println(BarTransitions.modeToString(transitions.getMode()));
     }
@@ -3652,14 +3416,10 @@
                 }
             }
             else if (Intent.ACTION_SCREEN_OFF.equals(action)) {
-                notifyNavigationBarScreenOn(false);
                 notifyHeadsUpScreenOff();
                 finishBarAnimations();
                 resetUserExpandedStates();
             }
-            else if (Intent.ACTION_SCREEN_ON.equals(action)) {
-                notifyNavigationBarScreenOn(true);
-            }
             else if (DevicePolicyManager.ACTION_SHOW_DEVICE_MONITORING_DIALOG.equals(action)) {
                 mQSPanel.showDeviceMonitoringDialog();
             }
@@ -3728,7 +3488,6 @@
             Log.v(TAG, "configuration changed: " + mContext.getResources().getConfiguration());
         }
 
-        repositionNavigationBar();
         updateRowStates();
         mScreenPinningRequest.onConfigurationChanged();
         mNetworkController.onConfigurationChanged();
@@ -3760,6 +3519,9 @@
         if (mSecurityController != null) {
             mSecurityController.onUserSwitched(mCurrentUserId);
         }
+        if (mNetworkController != null) {
+            mNetworkController.onUserSwitched(mCurrentUserId);
+        }
     }
 
     private void resetUserSetupObserver() {
@@ -3872,7 +3634,7 @@
     }
 
     public void onKeyguardOccludedChanged(boolean keyguardOccluded) {
-        mNavigationBarView.onKeyguardOccludedChanged(keyguardOccluded);
+        mNavigationBar.onKeyguardOccludedChanged(keyguardOccluded);
     }
 
     // State logging
@@ -3950,11 +3712,6 @@
         }
     };
 
-    @Override
-    public boolean shouldDisableNavbarGestures() {
-        return !isDeviceProvisioned() || (mDisabled1 & StatusBarManager.DISABLE_SEARCH) != 0;
-    }
-
     public void postQSRunnableDismissingKeyguard(final Runnable runnable) {
         mHandler.post(new Runnable() {
             @Override
@@ -4111,8 +3868,8 @@
                 if (mStatusBarView != null) {
                     mStatusBarView.getBarTransitions().transitionTo(barMode, animate);
                 }
-                if (mNavigationBarView != null) {
-                    mNavigationBarView.getBarTransitions().transitionTo(barMode, animate);
+                if (mNavigationBar != null) {
+                    mNavigationBar.getBarTransitions().transitionTo(barMode, animate);
                 }
             }
         }
@@ -4233,8 +3990,8 @@
                 mIconController.getTransitionsController().appTransitionStarting(
                         SystemClock.uptimeMillis(),
                         LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION);
-                if (mNavigationBarView != null) {
-                    mNavigationBarView.getLightTransitionsController().appTransitionStarting(
+                if (mNavigationBar != null) {
+                    mNavigationBar.doAppTransitionStarting(
                             SystemClock.uptimeMillis(),
                             LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION);
                 }
@@ -4318,14 +4075,8 @@
 
             // Disable layout transitions in navbar for this transition because the load is just
             // too heavy for the CPU and GPU on any device.
-            if (mNavigationBarView != null) {
-                mNavigationBarView.setLayoutTransitionsEnabled(false);
-                mNavigationBarView.postDelayed(new Runnable() {
-                    @Override
-                    public void run() {
-                        mNavigationBarView.setLayoutTransitionsEnabled(true);
-                    }
-                }, delay + StackStateAnimator.ANIMATION_DURATION_GO_TO_FULL_SHADE);
+            if (mNavigationBar != null) {
+                mNavigationBar.disableAnimationsDuringHide(delay);
             }
         } else if (!mNotificationPanel.isCollapsing()) {
             instantCollapseNotificationPanel();
@@ -4369,8 +4120,9 @@
         // bar.
         mKeyguardGoingAway = true;
         mIconController.getTransitionsController().appTransitionPending();
-        if (mNavigationBarView != null) {
-            mNavigationBarView.getLightTransitionsController().appTransitionPending();
+        if (mNavigationBar != null) {
+            mNavigationBar.setKeyguardGoingAway(true);
+            mNavigationBar.appTransitionPending();
         }
     }
 
@@ -4391,8 +4143,8 @@
                         - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
                 LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION);
         recomputeDisableFlags(fadeoutDuration > 0 /* animate */);
-        if (mNavigationBarView != null) {
-            mNavigationBarView.getLightTransitionsController().appTransitionStarting(
+        if (mNavigationBar != null) {
+            mNavigationBar.doAppTransitionStarting(
                     startTime - LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION,
                     LightBarTransitionsController.DEFAULT_TINT_ANIMATION_DURATION);
         }
@@ -4408,6 +4160,9 @@
     public void finishKeyguardFadingAway() {
         mKeyguardFadingAway = false;
         mKeyguardGoingAway = false;
+        if (mNavigationBar != null) {
+            mNavigationBar.setKeyguardGoingAway(false);
+        }
     }
 
     public void stopWaitingForKeyguardExit() {
@@ -4483,6 +4238,7 @@
         mDozeScrimController.setDozing(mDozing &&
                 mFingerprintUnlockController.getMode()
                         != FingerprintUnlockController.MODE_WAKE_AND_UNLOCK_PULSING, animate);
+        updateRowStates();
         Trace.endSection();
     }
 
@@ -4596,10 +4352,6 @@
         mStackScroller.setActivatedChild(view);
     }
 
-    public ButtonDispatcher getHomeButton() {
-        return mNavigationBarView.getHomeButton();
-    }
-
     /**
      * @param state The {@link StatusBarState} to set.
      */
@@ -4696,8 +4448,9 @@
         return getMaxKeyguardNotifications(false /* recompute */);
     }
 
+    // TODO: Figure out way to remove this.
     public NavigationBarView getNavigationBarView() {
-        return mNavigationBarView;
+        return (NavigationBarView) mNavigationBar.getView();
     }
 
     // ---------------------- DragDownHelper.OnDragDownListener ------------------------------------
@@ -4983,79 +4736,6 @@
         mDozeScrimController.onScreenTurnedOn();
     }
 
-    /**
-     * This handles long-press of both back and recents.  They are
-     * handled together to capture them both being long-pressed
-     * at the same time to exit screen pinning (lock task).
-     *
-     * When accessibility mode is on, only a long-press from recents
-     * is required to exit.
-     *
-     * In all other circumstances we try to pass through long-press events
-     * for Back, so that apps can still use it.  Which can be from two things.
-     * 1) Not currently in screen pinning (lock task).
-     * 2) Back is long-pressed without recents.
-     */
-    private boolean handleLongPressBackRecents(View v) {
-        try {
-            boolean sendBackLongPress = false;
-            IActivityManager activityManager = ActivityManagerNative.getDefault();
-            boolean touchExplorationEnabled = mAccessibilityManager.isTouchExplorationEnabled();
-            boolean inLockTaskMode = activityManager.isInLockTaskMode();
-            if (inLockTaskMode && !touchExplorationEnabled) {
-                long time = System.currentTimeMillis();
-                // If we recently long-pressed the other button then they were
-                // long-pressed 'together'
-                if ((time - mLastLockToAppLongPress) < LOCK_TO_APP_GESTURE_TOLERENCE) {
-                    activityManager.stopLockTaskMode();
-                    // When exiting refresh disabled flags.
-                    mNavigationBarView.setDisabledFlags(mDisabled1, true);
-                    return true;
-                } else if ((v.getId() == R.id.back)
-                        && !mNavigationBarView.getRecentsButton().getCurrentView().isPressed()) {
-                    // If we aren't pressing recents right now then they presses
-                    // won't be together, so send the standard long-press action.
-                    sendBackLongPress = true;
-                }
-                mLastLockToAppLongPress = time;
-            } else {
-                // If this is back still need to handle sending the long-press event.
-                if (v.getId() == R.id.back) {
-                    sendBackLongPress = true;
-                } else if (touchExplorationEnabled && inLockTaskMode) {
-                    // When in accessibility mode a long press that is recents (not back)
-                    // should stop lock task.
-                    activityManager.stopLockTaskMode();
-                    // When exiting refresh disabled flags.
-                    mNavigationBarView.setDisabledFlags(mDisabled1, true);
-                    return true;
-                } else if (v.getId() == R.id.recent_apps) {
-                    return handleLongPressRecents();
-                }
-            }
-            if (sendBackLongPress) {
-                KeyButtonView keyButtonView = (KeyButtonView) v;
-                keyButtonView.sendEvent(KeyEvent.ACTION_DOWN, KeyEvent.FLAG_LONG_PRESS);
-                keyButtonView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_LONG_CLICKED);
-                return true;
-            }
-        } catch (RemoteException e) {
-            Log.d(TAG, "Unable to reach activity manager", e);
-        }
-        return false;
-    }
-
-    private boolean handleLongPressRecents() {
-        if (mRecents == null || !ActivityManager.supportsMultiWindow()
-                || !getComponent(Divider.class).getView().getSnapAlgorithm()
-                .isSplitScreenFeasible()) {
-            return false;
-        }
-
-        return toggleSplitScreenMode(MetricsEvent.ACTION_WINDOW_DOCK_LONGPRESS,
-                MetricsEvent.ACTION_WINDOW_UNDOCK_LONGPRESS);
-    }
-
     @Override
     public void showScreenPinningRequest(int taskId) {
         if (mKeyguardMonitor.isShowing()) {
@@ -5088,37 +4768,25 @@
 
     @Override
     public void appTransitionPending() {
-
         // Use own timings when Keyguard is going away, see keyguardGoingAway and
         // setKeyguardFadingAway
         if (!mKeyguardFadingAway) {
             mIconController.getTransitionsController().appTransitionPending();
-            if (mNavigationBarView != null) {
-                mNavigationBarView.getLightTransitionsController().appTransitionPending();
-            }
         }
     }
 
     @Override
     public void appTransitionCancelled() {
         mIconController.getTransitionsController().appTransitionCancelled();
-        if (mNavigationBarView != null) {
-            mNavigationBarView.getLightTransitionsController().appTransitionCancelled();
-        }
         EventBus.getDefault().send(new AppTransitionFinishedEvent());
     }
 
     @Override
     public void appTransitionStarting(long startTime, long duration) {
-
         // Use own timings when Keyguard is going away, see keyguardGoingAway and
         // setKeyguardFadingAway.
         if (!mKeyguardGoingAway) {
             mIconController.getTransitionsController().appTransitionStarting(startTime, duration);
-            if (mNavigationBarView != null) {
-                mNavigationBarView.getLightTransitionsController().appTransitionStarting(
-                        startTime, duration);
-            }
         }
         if (mIconPolicy != null) {
             mIconPolicy.appTransitionStarting(startTime, duration);
@@ -5188,6 +4856,10 @@
         Trace.endSection();
     }
 
+    public boolean isKeyguardShowing() {
+        return mStatusBarKeyguardViewManager.isShowing();
+    }
+
     private final class ShadeUpdates {
         private final ArraySet<String> mVisibleNotifications = new ArraySet<String>();
         private final ArraySet<String> mNewVisibleNotifications = new ArraySet<String>();
@@ -5237,9 +4909,9 @@
             }
         }
 
-        public void fireBuzzBeepBlinked() {
+        public void fireNotificationHeadsUp() {
             for (Callback callback : mCallbacks) {
-                callback.onBuzzBeepBlinked();
+                callback.onNotificationHeadsUp();
             }
         }
 
@@ -5283,12 +4955,14 @@
                 public void onPulseStarted() {
                     callback.onPulseStarted();
                     mStackScroller.setPulsing(true);
+                    mVisualStabilityManager.setPulsing(true);
                 }
 
                 @Override
                 public void onPulseFinished() {
                     callback.onPulseFinished();
                     mStackScroller.setPulsing(false);
+                    mVisualStabilityManager.setPulsing(false);
                 }
             }, reason);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 227ebdf..d4cf533 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -52,6 +52,7 @@
 import com.android.systemui.qs.tiles.HotspotTile;
 import com.android.systemui.qs.tiles.IntentTile;
 import com.android.systemui.qs.tiles.LocationTile;
+import com.android.systemui.qs.tiles.NfcTile;
 import com.android.systemui.qs.tiles.NightDisplayTile;
 import com.android.systemui.qs.tiles.RotationLockTile;
 import com.android.systemui.qs.tiles.UserTile;
@@ -440,6 +441,7 @@
         else if (tileSpec.equals("battery")) return new BatteryTile(this);
         else if (tileSpec.equals("saver")) return new DataSaverTile(this);
         else if (tileSpec.equals("night")) return new NightDisplayTile(this);
+        else if (tileSpec.equals("nfc")) return new NfcTile(this);
         // Intent tiles.
         else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
         else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
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 517551d..8fcbf38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -338,13 +338,13 @@
     private void setCurrentScrimAlpha(View scrim, float alpha) {
         if (scrim == mScrimBehind) {
             mCurrentBehindAlpha = alpha;
+            mLightBarController.setScrimAlpha(mCurrentBehindAlpha);
         } else if (scrim == mScrimInFront) {
             mCurrentInFrontAlpha = alpha;
         } else {
             alpha = Math.max(0.0f, Math.min(1.0f, alpha));
             mCurrentHeadsUpAlpha = alpha;
         }
-        mLightBarController.setScrimAlpha(mCurrentBehindAlpha);
     }
 
     protected void updateScrimColor(View scrim) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index 06cd769..395e8f2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -359,6 +359,7 @@
     private boolean mInHeadsUpPinnedMode;
     private boolean mHeadsUpAnimatingAway;
     private int mStatusBarState;
+    private int mCachedBackgroundColor;
 
     public NotificationStackScrollLayout(Context context) {
         this(context, null);
@@ -445,8 +446,11 @@
                         + alphaInv * Color.green(scrimColor)),
                 (int) (mBackgroundFadeAmount * Color.blue(mBgColor)
                         + alphaInv * Color.blue(scrimColor)));
-        mBackgroundPaint.setColor(color);
-        invalidate();
+        if (mCachedBackgroundColor != color) {
+            mCachedBackgroundColor = color;
+            mBackgroundPaint.setColor(color);
+            invalidate();
+        }
     }
 
     private void initView(Context context) {
@@ -1879,12 +1883,16 @@
         float previousIncreasedAmount = 0.0f;
         int numShownItems = 0;
         boolean finish = false;
+        int maxDisplayedNotifications = mAmbientState.isDark()
+                ? (mPulsing ? 1 : 0)
+                : mMaxDisplayedNotifications;
+
         for (int i = 0; i < getChildCount(); i++) {
             ExpandableView expandableView = (ExpandableView) getChildAt(i);
             if (expandableView.getVisibility() != View.GONE
                     && !expandableView.hasNoContentHeight()) {
-                if (mMaxDisplayedNotifications != -1
-                        && numShownItems >= mMaxDisplayedNotifications) {
+                if (maxDisplayedNotifications != -1
+                        && numShownItems >= maxDisplayedNotifications) {
                     expandableView = mShelf;
                     finish = true;
                 }
@@ -2092,9 +2100,14 @@
      * Update the background bounds to the new desired bounds
      */
     private void updateBackgroundBounds() {
-        getLocationInWindow(mTempInt2);
-        mBackgroundBounds.left = mTempInt2[0];
-        mBackgroundBounds.right = mTempInt2[0] + getWidth();
+        if (mAmbientState.isPanelFullWidth()) {
+            mBackgroundBounds.left = 0;
+            mBackgroundBounds.right = getWidth();
+        } else {
+            getLocationInWindow(mTempInt2);
+            mBackgroundBounds.left = mTempInt2[0];
+            mBackgroundBounds.right = mTempInt2[0] + getWidth();
+        }
         if (!mIsExpanded) {
             mBackgroundBounds.top = 0;
             mBackgroundBounds.bottom = 0;
@@ -3477,6 +3490,8 @@
             updateBackground();
             setWillNotDraw(false);
         }
+        updateContentHeight();
+        notifyHeightChangeListener(mShelf);
     }
 
     private void setBackgroundFadeAmount(float fadeAmount) {
@@ -3912,6 +3927,8 @@
     public void setPulsing(boolean pulsing) {
         mPulsing = pulsing;
         updateNotificationAnimationStates();
+        updateContentHeight();
+        notifyHeightChangeListener(mShelf);
     }
 
     public void setFadingOut(boolean fadingOut) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
index 89d4b00..9b8183b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -106,11 +106,6 @@
     protected void updateNotifications() {
     }
 
-    @Override
-    public boolean shouldDisableNavbarGestures() {
-        return true;
-    }
-
     public View getStatusBarView() {
         return null;
     }
@@ -143,10 +138,6 @@
     }
 
     @Override
-    protected void refreshLayout(int layoutDirection) {
-    }
-
-    @Override
     public void onActivated(ActivatableNotificationView view) {
     }
 
diff --git a/packages/SystemUI/tests/Android.mk b/packages/SystemUI/tests/Android.mk
index e96ea19..c627e22 100644
--- a/packages/SystemUI/tests/Android.mk
+++ b/packages/SystemUI/tests/Android.mk
@@ -46,7 +46,8 @@
     android-support-test \
     mockito-updated-target-minus-junit4 \
     SystemUI-proto \
-    SystemUI-tags
+    SystemUI-tags \
+    legacy-android-test
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common android.car
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
index be6290b..76bb6c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/notification/VisualStabilityManagerTest.java
@@ -150,4 +150,28 @@
         mVisualStabilityManager.onReorderingFinished();
         assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false);
     }
+
+    @Test
+    public void testPulsing() {
+        mVisualStabilityManager.setPulsing(true);
+        assertEquals(mVisualStabilityManager.canReorderNotification(mRow), false);
+        mVisualStabilityManager.setPulsing(false);
+        assertEquals(mVisualStabilityManager.canReorderNotification(mRow), true);
+    }
+
+    @Test
+    public void testReorderingAllowedChanges_Pulsing() {
+        mVisualStabilityManager.setPulsing(true);
+        assertEquals(mVisualStabilityManager.isReorderingAllowed(), false);
+        mVisualStabilityManager.setPulsing(false);
+        assertEquals(mVisualStabilityManager.isReorderingAllowed(), true);
+    }
+
+    @Test
+    public void testCallBackCalled_Pulsing() {
+        mVisualStabilityManager.setPulsing(true);
+        mVisualStabilityManager.addReorderingAllowedCallback(mCallback);
+        mVisualStabilityManager.setPulsing(false);
+        verify(mCallback).onReorderingAllowed();
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java
new file mode 100644
index 0000000..3bb9f5f
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+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.view.View;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NotificationContentViewTest {
+
+    NotificationContentView mView;
+    Context mContext;
+
+    @Before
+    public void setup() {
+        ExpandableNotificationRow rowMock = mock(ExpandableNotificationRow.class);
+        when(rowMock.getIntrinsicHeight()).thenReturn(10);
+
+        mContext = InstrumentationRegistry.getTargetContext();
+        mView = new NotificationContentView(mContext, null);
+        mView.setContainingNotification(rowMock);
+        mView.setHeights(10, 20, 30, 40);
+
+        mView.setContractedChild(createViewWithHeight(10));
+        mView.setExpandedChild(createViewWithHeight(20));
+        mView.setHeadsUpChild(createViewWithHeight(30));
+        mView.setAmbientChild(createViewWithHeight(40));
+
+        mView.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
+        mView.layout(0, 0, mView.getMeasuredWidth(), mView.getMeasuredHeight());
+    }
+
+    private View createViewWithHeight(int height) {
+        View view = new View(mContext, null);
+        view.setMinimumHeight(height);
+        return view;
+    }
+
+    @Test
+    @UiThreadTest
+    public void animationStartType_getsClearedAfterUpdatingVisibilitiesWithoutAnimation() {
+        mView.setHeadsUp(true);
+        mView.setDark(true, false, 0);
+        mView.setDark(false, true, 0);
+        mView.setHeadsUpAnimatingAway(true);
+        Assert.assertFalse(mView.isAnimatingVisibleType());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
new file mode 100644
index 0000000..7d9e073
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/StatusBarIconViewTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar;
+
+import android.graphics.drawable.Icon;
+import android.os.Debug;
+import android.os.UserHandle;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.statusbar.StatusBarIcon;
+import com.android.systemui.R;
+import com.android.systemui.SysuiTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static junit.framework.Assert.assertNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class StatusBarIconViewTest extends SysuiTestCase {
+
+    private StatusBarIconView mIconView;
+    private StatusBarIcon mStatusBarIcon = mock(StatusBarIcon.class);
+
+    @Before
+    public void setUp() {
+        mIconView = new StatusBarIconView(getContext(), "slot", null);
+        mStatusBarIcon = new StatusBarIcon(UserHandle.ALL, getContext().getPackageName(),
+                Icon.createWithResource(getContext(), R.drawable.ic_android), 0, 0, "");
+    }
+
+    @Test
+    public void testSetClearsGrayscale() {
+        mIconView.setTag(R.id.icon_is_grayscale, true);
+        mIconView.set(mStatusBarIcon);
+        assertNull(mIconView.getTag(R.id.icon_is_grayscale));
+    }
+
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
new file mode 100644
index 0000000..34743ff
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java
@@ -0,0 +1,40 @@
+/*
+ * 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.phone;
+
+import static org.mockito.Mockito.mock;
+
+import com.android.systemui.FragmentTestCase;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.Before;
+
+public class NavigationBarFragmentTest extends FragmentTestCase {
+
+    public NavigationBarFragmentTest() {
+        super(NavigationBarFragment.class);
+    }
+
+    @Before
+    public void setup() {
+        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+        mContext.putComponent(PhoneStatusBar.class, mock(PhoneStatusBar.class));
+        mContext.putComponent(Recents.class, mock(Recents.class));
+        mContext.putComponent(Divider.class, mock(Divider.class));
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
index 710f88a..62c007f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/utils/TestableContext.java
@@ -31,10 +31,11 @@
 import android.provider.Settings;
 import android.util.ArrayMap;
 
+import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.utils.leaks.Tracker;
 import com.android.systemui.SysuiTestCase;
 
-public class TestableContext extends ContextWrapper {
+public class TestableContext extends ContextWrapper implements SysUiServiceProvider {
 
     private final FakeContentResolver mFakeContentResolver;
     private final FakeSettingsProvider mSettingsProvider;
@@ -42,6 +43,7 @@
     private ArrayMap<String, Object> mMockSystemServices;
     private ArrayMap<ComponentName, IBinder> mMockServices;
     private ArrayMap<ServiceConnection, ComponentName> mActiveServices;
+    private ArrayMap<Class<?>, Object> mComponents;
 
     private PackageManager mMockPackageManager;
     private Tracker mReceiver;
@@ -201,4 +203,14 @@
         if (mComponent != null) mComponent.getLeakInfo(callback).clearAllocations();
         super.unregisterComponentCallbacks(callback);
     }
+
+    @SuppressWarnings("unchecked")
+    public <T> T getComponent(Class<T> interfaceType) {
+        return (T) (mComponents != null ? mComponents.get(interfaceType) : null);
+    }
+
+    public <T, C extends T> void putComponent(Class<T> interfaceType, C component) {
+        mComponents = lazyInit(mComponents);
+        mComponents.put(interfaceType, component);
+    }
 }
diff --git a/packages/WAPPushManager/tests/Android.mk b/packages/WAPPushManager/tests/Android.mk
index 7128b0d..1dea798 100644
--- a/packages/WAPPushManager/tests/Android.mk
+++ b/packages/WAPPushManager/tests/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/packages/WallpaperCropper/Android.mk b/packages/WallpaperCropper/Android.mk
index 09b41fd..d8fb7a4 100644
--- a/packages/WallpaperCropper/Android.mk
+++ b/packages/WallpaperCropper/Android.mk
@@ -6,7 +6,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := telephony-common
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 junit
 
 LOCAL_PACKAGE_NAME := WallpaperCropper
 LOCAL_CERTIFICATE := platform
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index dc92f56..62ea9e3 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -3173,9 +3173,9 @@
 
     // These values should never appear in log outputs - they are reserved for
     // internal Tron use.
-    RESERVED_FOR_LOGBUILDER_VIEW = 757;
-    RESERVED_FOR_LOGBUILDER_CATEGORY = 758;
-    RESERVED_FOR_LOGBUILDER_TYPE = 759;
+    RESERVED_FOR_LOGBUILDER_CATEGORY = 757;
+    RESERVED_FOR_LOGBUILDER_TYPE = 758;
+    RESERVED_FOR_LOGBUILDER_SUBTYPE = 759;
 
     // ACTION: "Do not show again" was enabled in the support disclaimer and the
     // user accepted
@@ -3191,6 +3191,118 @@
     // ACTION: Clicking on any search result in Settings.
     ACTION_CLICK_SETTINGS_SEARCH_RESULT = 763;
 
+    // ACTION: Allow Battery optimization for an app
+    APP_SPECIAL_PERMISSION_BATTERY_ALLOW = 764;
+
+    // ACTION: Deny Battery optimization for an app
+    APP_SPECIAL_PERMISSION_BATTERY_DENY = 765;
+
+    // ACTION: Enable Device Admin app
+    APP_SPECIAL_PERMISSION_ADMIN_ALLOW = 766;
+
+    // ACTION: Disable Device Admin app
+    APP_SPECIAL_PERMISSION_ADMIN_DENY = 767;
+
+    // ACTION: Allow "Do Not Disturb access" for an app
+    APP_SPECIAL_PERMISSION_DND_ALLOW = 768;
+
+    // ACTION: Deny "Do Not Disturb access" for an app
+    APP_SPECIAL_PERMISSION_DND_DENY = 769;
+
+    // ACTION: Allow "Draw over other apps" for an app
+    APP_SPECIAL_PERMISSION_APPDRAW_ALLOW = 770;
+
+    // ACTION: Deny "Draw over other apps" for an app
+    APP_SPECIAL_PERMISSION_APPDRAW_DENY = 771;
+
+    // ACTION: Allow "VR helper services" for an app
+    APP_SPECIAL_PERMISSION_VRHELPER_ALLOW = 772;
+
+    // ACTION: Deny "VR helper services" for an app
+    APP_SPECIAL_PERMISSION_VRHELPER_DENY = 773;
+
+    // ACTION: Allow "Modify system settings" for an app
+    APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_ALLOW = 774;
+
+    // ACTION: Deny "Modify system settings" for an app
+    APP_SPECIAL_PERMISSION_SETTINGS_CHANGE_DENY = 775;
+
+    // ACTION: Allow "Notification access" for an app
+    APP_SPECIAL_PERMISSION_NOTIVIEW_ALLOW = 776;
+
+    // ACTION: Deny "Notification access" for an app
+    APP_SPECIAL_PERMISSION_NOTIVIEW_DENY = 777;
+
+    // ACTION: "Premium SMS access" for an app - "ask user" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_ASK = 778;
+
+    // ACTION: "Premium SMS access" for an app - "never allow" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_DENY = 779;
+
+    // ACTION: "Premium SMS access" for an app - "always allow" option
+    APP_SPECIAL_PERMISSION_PREMIUM_SMS_ALWAYS_ALLOW = 780;
+
+    // ACTION: Allow "Unrestricted data access" for an app
+    APP_SPECIAL_PERMISSION_UNL_DATA_ALLOW = 781;
+
+    // ACTION: Deny "Unrestricted data access" for an app
+    APP_SPECIAL_PERMISSION_UNL_DATA_DENY = 782;
+
+    // ACTION: Allow "Usage access" for an app
+    APP_SPECIAL_PERMISSION_USAGE_VIEW_ALLOW = 783;
+
+    // ACTION: Deny "Usage access" for an app
+    APP_SPECIAL_PERMISSION_USAGE_VIEW_DENY = 784;
+
+    // OPEN: Settings > Apps > Default Apps > Default browser
+    DEFAULT_BROWSER_PICKER = 785;
+
+    // OPEN: Settings > Apps > Default Apps > Default emergency app
+    DEFAULT_EMERGENCY_APP_PICKER = 786;
+
+    // OPEN: Settings > Apps > Default Apps > Default home
+    DEFAULT_HOME_PICKER = 787;
+
+    // OPEN: Settings > Apps > Default Apps > Default phone
+    DEFAULT_PHONE_PICKER = 788;
+
+    // OPEN: Settings > Apps > Default Apps > Default sms
+    DEFAULT_SMS_PICKER = 789;
+
+    // OPEN: Settings > Apps > Default Apps > Default notification assistant
+    DEFAULT_NOTIFICATION_ASSISTANT = 790;
+
+    // OPEN: Settings > Apps > Default Apps > Warning dialog to confirm selection
+    DEFAULT_APP_PICKER_CONFIRMATION_DIALOG = 791;
+
+
+    // OPEN: Settings > Apps > Default Apps > Default auto-fill app
+    DEFAULT_AUTO_FILL_PICKER = 792;
+
+    // These values should never appear in log outputs - they are reserved for
+    // internal Tron use.
+    NOTIFICATION_SINCE_CREATE_MILLIS = 793;
+    NOTIFICATION_SINCE_VISIBLE_MILLIS = 794;
+    NOTIFICATION_SINCE_UPDATE_MILLIS = 795;
+    NOTIFICATION_ID = 796;
+    NOTIFICATION_TAG = 797;
+    NOTIFICATION_SHADE_INDEX = 798;
+    RESERVED_FOR_LOGBUILDER_NAME = 799;
+
+    // OPEN: QS NFC tile shown
+    // ACTION: QS NFC tile tapped
+    // CATEGORY: QUICK_SETTINGS
+    QS_NFC = 800;
+
+    // These values should never appear in log outputs - they are reserved for
+    // internal Tron use.
+    RESERVED_FOR_LOGBUILDER_BUCKET = 801;
+    RESERVED_FOR_LOGBUILDER_VALUE = 802;
+    RESERVED_FOR_LOGBUILDER_COUNTER = 803;
+    RESERVED_FOR_LOGBUILDER_HISTOGRAM = 804;
+    RESERVED_FOR_LOGBUILDER_TIMESTAMP = 805;
+    RESERVED_FOR_LOGBUILDER_PACKAGENAME = 806;
+
     // ---- End O Constants, all O constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/sax/tests/saxtests/Android.mk b/sax/tests/saxtests/Android.mk
index 836711b..d3fbd05 100644
--- a/sax/tests/saxtests/Android.mk
+++ b/sax/tests/saxtests/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := FrameworksSaxTests
 
 include $(BUILD_PACKAGE)
diff --git a/services/Android.mk b/services/Android.mk
index 0d57efe..e760fe2 100644
--- a/services/Android.mk
+++ b/services/Android.mk
@@ -36,7 +36,9 @@
     voiceinteraction
 
 # The convention is to name each service module 'services.$(module_name)'
-LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services))
+LOCAL_STATIC_JAVA_LIBRARIES := $(addprefix services.,$(services)) \
+    android.hidl.base@1.0-java-static \
+    android.hardware.biometrics.fingerprint@2.1-java-static
 
 ifeq ($(EMMA_INSTRUMENT_FRAMEWORK),true)
 LOCAL_EMMA_INSTRUMENT := true
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index b34e4e4..ece5149 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -97,6 +97,7 @@
 import com.android.internal.os.SomeArgs;
 import com.android.server.LocalServices;
 
+import com.android.server.policy.AccessibilityShortcutController;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -1489,6 +1490,7 @@
         mInitialized = true;
         updateLegacyCapabilitiesLocked(userState);
         updateServicesLocked(userState);
+        updateAccessibilityShortcutLocked(userState);
         updateWindowsForAccessibilityCallbackLocked(userState);
         updateAccessibilityFocusBehaviorLocked(userState);
         updateFilterKeyEventsLocked(userState);
@@ -1613,7 +1615,7 @@
         somethingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
         somethingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
         somethingChanged |= readAutoclickEnabledSettingLocked(userState);
-
+        somethingChanged |= readAccessibilityShortcutSettingLocked(userState);
         return somethingChanged;
     }
 
@@ -1722,6 +1724,50 @@
         }
     }
 
+    private boolean readAccessibilityShortcutSettingLocked(UserState userState) {
+        String componentNameToEnableString = AccessibilityShortcutController
+                .getTargetServiceComponentNameString(mContext, userState.mUserId);
+        if ((componentNameToEnableString == null) || componentNameToEnableString.isEmpty()) {
+            if (userState.mServiceToEnableWithShortcut == null) {
+                return false;
+            }
+            userState.mServiceToEnableWithShortcut = null;
+            return true;
+        }
+        ComponentName componentNameToEnable =
+            ComponentName.unflattenFromString(componentNameToEnableString);
+        if (componentNameToEnable.equals(userState.mServiceToEnableWithShortcut)) {
+            return false;
+        }
+        userState.mServiceToEnableWithShortcut = componentNameToEnable;
+        return true;
+    }
+
+    /**
+     * Check if the service that will be enabled by the shortcut is installed. If it isn't,
+     * clear the value and the associated setting so a sideloaded service can't spoof the
+     * package name of the default service.
+     *
+     * @param userState
+     */
+    private void updateAccessibilityShortcutLocked(UserState userState) {
+        if (userState.mServiceToEnableWithShortcut == null) {
+            return;
+        }
+        boolean shortcutServiceIsInstalled = false;
+        for (int i = 0; i < userState.mInstalledServices.size(); i++) {
+            if (userState.mInstalledServices.get(i).getComponentName()
+                    .equals(userState.mServiceToEnableWithShortcut)) {
+                shortcutServiceIsInstalled = true;
+            }
+        }
+        if (!shortcutServiceIsInstalled) {
+            userState.mServiceToEnableWithShortcut = null;
+            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "", userState.mUserId);
+        }
+    }
+
     private boolean canRequestAndRequestsTouchExplorationLocked(Service service) {
         // Service not ready or cannot request the feature - well nothing to do.
         if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) {
@@ -1895,44 +1941,63 @@
     }
 
     /**
+     * AIDL-exposed method to be called when the accessibility shortcut is enabled. Requires
+     * permission to write secure settings, since someone with that permission can enable
+     * accessibility services themselves.
+     */
+    public void performAccessibilityShortcut() {
+        if ((UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID)
+                && (mContext.checkCallingPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+                != PackageManager.PERMISSION_GRANTED)) {
+            throw new SecurityException(
+                    "performAccessibilityShortcut requires the WRITE_SECURE_SETTINGS permission");
+        }
+        synchronized(mLock) {
+            UserState userState = getUserStateLocked(mCurrentUserId);
+            ComponentName serviceName = userState.mServiceToEnableWithShortcut;
+            if (serviceName == null) {
+                return;
+            }
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                if (userState.mComponentNameToServiceMap.get(serviceName) == null) {
+                    enableAccessibilityServiceLocked(serviceName, mCurrentUserId);
+                } else {
+                    disableAccessibilityServiceLocked(serviceName, mCurrentUserId);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+    };
+
+    /**
      * Enables accessibility service specified by {@param componentName} for the {@param userId}.
      */
-    public void enableAccessibilityService(ComponentName componentName, int userId) {
-        synchronized(mLock) {
-            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-                throw new SecurityException("only SYSTEM can call enableAccessibilityService.");
-            }
+    private void enableAccessibilityServiceLocked(ComponentName componentName, int userId) {
+        SettingsStringHelper settingsHelper = new SettingsStringHelper(
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
+        settingsHelper.addService(componentName);
+        settingsHelper.writeToSettings();
 
-            SettingsStringHelper settingsHelper = new SettingsStringHelper(
-                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
-            settingsHelper.addService(componentName);
-            settingsHelper.writeToSettings();
-
-            UserState userState = getUserStateLocked(userId);
-            if (userState.mEnabledServices.add(componentName)) {
-                onUserStateChangedLocked(userState);
-            }
+        UserState userState = getUserStateLocked(userId);
+        if (userState.mEnabledServices.add(componentName)) {
+            onUserStateChangedLocked(userState);
         }
     }
 
     /**
      * Disables accessibility service specified by {@param componentName} for the {@param userId}.
      */
-    public void disableAccessibilityService(ComponentName componentName, int userId) {
-        synchronized(mLock) {
-            if (Binder.getCallingUid() != Process.SYSTEM_UID) {
-                throw new SecurityException("only SYSTEM can call disableAccessibility");
-            }
+    private void disableAccessibilityServiceLocked(ComponentName componentName, int userId) {
+        SettingsStringHelper settingsHelper = new SettingsStringHelper(
+                Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
+        settingsHelper.deleteService(componentName);
+        settingsHelper.writeToSettings();
 
-            SettingsStringHelper settingsHelper = new SettingsStringHelper(
-                    Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, userId);
-            settingsHelper.deleteService(componentName);
-            settingsHelper.writeToSettings();
-
-            UserState userState = getUserStateLocked(userId);
-            if (userState.mEnabledServices.remove(componentName)) {
-                onUserStateChangedLocked(userState);
-            }
+        UserState userState = getUserStateLocked(userId);
+        if (userState.mEnabledServices.remove(componentName)) {
+            onUserStateChangedLocked(userState);
         }
     }
 
@@ -4307,6 +4372,8 @@
 
         public ComponentName mServiceChangingSoftKeyboardMode;
 
+        public ComponentName mServiceToEnableWithShortcut;
+
         public int mLastSentClientState = -1;
 
         public int mSoftKeyboardShowMode = 0;
@@ -4439,6 +4506,9 @@
         private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
 
+        private final Uri mAccessibilityShortcutServiceIdUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE);
+
         public AccessibilityContentObserver(Handler handler) {
             super(handler);
         }
@@ -4467,6 +4537,8 @@
                     mHighTextContrastUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
                     mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -4519,6 +4591,10 @@
                         notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode);
                         onUserStateChangedLocked(userState);
                     }
+                } else if (mAccessibilityShortcutServiceIdUri.equals(uri)) {
+                    if (readAccessibilityShortcutSettingLocked(userState)) {
+                        onUserStateChangedLocked(userState);
+                    }
                 }
             }
         }
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 87eb380..3523706 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -126,6 +126,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
 
 class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBackupProvider,
         OnCrossProfileWidgetProvidersChangeListener {
@@ -152,6 +153,8 @@
     // Bump if the stored widgets need to be upgraded.
     private static final int CURRENT_VERSION = 1;
 
+    private static final AtomicLong REQUEST_COUNTER = new AtomicLong();
+
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -771,7 +774,8 @@
             LongSparseArray<PendingHostUpdate> updatesMap = new LongSparseArray<>();
             for (int i = 0; i < N; i++) {
                 if (host.getPendingUpdatesForId(appWidgetIds[i], updatesMap)) {
-                    // We key the updates based on time, so that the values are sorted by time.
+                    // We key the updates based on request id, so that the values are sorted in the
+                    // order they were received.
                     int M = updatesMap.size();
                     for (int j = 0; j < M; j++) {
                         outUpdates.add(updatesMap.valueAt(j));
@@ -1854,9 +1858,9 @@
             // method with a wrong id. In that case, ignore the call.
             return;
         }
-        long requestTime = SystemClock.uptimeMillis();
+        long requestId = REQUEST_COUNTER.incrementAndGet();
         if (widget != null) {
-            widget.updateTimes.put(viewId, requestTime);
+            widget.updateRequestIds.put(viewId, requestId);
         }
         if (widget == null || widget.host == null || widget.host.zombie
                 || widget.host.callbacks == null || widget.provider == null
@@ -1867,7 +1871,7 @@
         SomeArgs args = SomeArgs.obtain();
         args.arg1 = widget.host;
         args.arg2 = widget.host.callbacks;
-        args.arg3 = requestTime;
+        args.arg3 = requestId;
         args.argi1 = widget.appWidgetId;
         args.argi2 = viewId;
 
@@ -1878,10 +1882,10 @@
 
 
     private void handleNotifyAppWidgetViewDataChanged(Host host, IAppWidgetHost callbacks,
-            int appWidgetId, int viewId, long requestTime) {
+            int appWidgetId, int viewId, long requestId) {
         try {
             callbacks.viewDataChanged(appWidgetId, viewId);
-            host.lastWidgetUpdateTime = requestTime;
+            host.lastWidgetUpdateRequestId = requestId;
         } catch (RemoteException re) {
             // It failed; remove the callback. No need to prune because
             // we know that this host is still referenced by this instance.
@@ -1928,9 +1932,9 @@
     }
 
     private void scheduleNotifyUpdateAppWidgetLocked(Widget widget, RemoteViews updateViews) {
-        long requestTime = SystemClock.uptimeMillis();
+        long requestId = REQUEST_COUNTER.incrementAndGet();
         if (widget != null) {
-            widget.updateTimes.put(ID_VIEWS_UPDATE, requestTime);
+            widget.updateRequestIds.put(ID_VIEWS_UPDATE, requestId);
         }
         if (widget == null || widget.provider == null || widget.provider.zombie
                 || widget.host.callbacks == null || widget.host.zombie) {
@@ -1941,7 +1945,7 @@
         args.arg1 = widget.host;
         args.arg2 = widget.host.callbacks;
         args.arg3 = (updateViews != null) ? updateViews.clone() : null;
-        args.arg4 = requestTime;
+        args.arg4 = requestId;
         args.argi1 = widget.appWidgetId;
 
         mCallbackHandler.obtainMessage(
@@ -1950,10 +1954,10 @@
     }
 
     private void handleNotifyUpdateAppWidget(Host host, IAppWidgetHost callbacks,
-            int appWidgetId, RemoteViews views, long requestTime) {
+            int appWidgetId, RemoteViews views, long requestId) {
         try {
             callbacks.updateAppWidget(appWidgetId, views);
-            host.lastWidgetUpdateTime = requestTime;
+            host.lastWidgetUpdateRequestId = requestId;
         } catch (RemoteException re) {
             synchronized (mLock) {
                 Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -1963,11 +1967,11 @@
     }
 
     private void scheduleNotifyProviderChangedLocked(Widget widget) {
-        long requestTime = SystemClock.uptimeMillis();
+        long requestId = REQUEST_COUNTER.incrementAndGet();
         if (widget != null) {
             // When the provider changes, reset everything else.
-            widget.updateTimes.clear();
-            widget.updateTimes.append(ID_PROVIDER_CHANGED, requestTime);
+            widget.updateRequestIds.clear();
+            widget.updateRequestIds.append(ID_PROVIDER_CHANGED, requestId);
         }
         if (widget == null || widget.provider == null || widget.provider.zombie
                 || widget.host.callbacks == null || widget.host.zombie) {
@@ -1978,7 +1982,7 @@
         args.arg1 = widget.host;
         args.arg2 = widget.host.callbacks;
         args.arg3 = widget.provider.info;
-        args.arg4 = requestTime;
+        args.arg4 = requestId;
         args.argi1 = widget.appWidgetId;
 
         mCallbackHandler.obtainMessage(
@@ -1987,10 +1991,10 @@
     }
 
     private void handleNotifyProviderChanged(Host host, IAppWidgetHost callbacks,
-            int appWidgetId, AppWidgetProviderInfo info, long requestTime) {
+            int appWidgetId, AppWidgetProviderInfo info, long requestId) {
         try {
             callbacks.providerChanged(appWidgetId, info);
-            host.lastWidgetUpdateTime = requestTime;
+            host.lastWidgetUpdateRequestId = requestId;
         } catch (RemoteException re) {
             synchronized (mLock){
                 Slog.e(TAG, "Widget host dead: " + host.id, re);
@@ -3463,11 +3467,11 @@
                     Host host = (Host) args.arg1;
                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
                     RemoteViews views = (RemoteViews) args.arg3;
-                    long requestTime = (Long) args.arg4;
+                    long requestId = (Long) args.arg4;
                     final int appWidgetId = args.argi1;
                     args.recycle();
 
-                    handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views, requestTime);
+                    handleNotifyUpdateAppWidget(host, callbacks, appWidgetId, views, requestId);
                 } break;
 
                 case MSG_NOTIFY_PROVIDER_CHANGED: {
@@ -3475,11 +3479,11 @@
                     Host host = (Host) args.arg1;
                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
                     AppWidgetProviderInfo info = (AppWidgetProviderInfo)args.arg3;
-                    long requestTime = (Long) args.arg4;
+                    long requestId = (Long) args.arg4;
                     final int appWidgetId = args.argi1;
                     args.recycle();
 
-                    handleNotifyProviderChanged(host, callbacks, appWidgetId, info, requestTime);
+                    handleNotifyProviderChanged(host, callbacks, appWidgetId, info, requestId);
                 } break;
 
                 case MSG_NOTIFY_PROVIDERS_CHANGED: {
@@ -3495,13 +3499,13 @@
                     SomeArgs args = (SomeArgs) message.obj;
                     Host host = (Host) args.arg1;
                     IAppWidgetHost callbacks = (IAppWidgetHost) args.arg2;
-                    long requestTime = (Long) args.arg3;
+                    long requestId = (Long) args.arg3;
                     final int appWidgetId = args.argi1;
                     final int viewId = args.argi2;
                     args.recycle();
 
                     handleNotifyAppWidgetViewDataChanged(host, callbacks, appWidgetId, viewId,
-                            requestTime);
+                            requestId);
                 } break;
             }
         }
@@ -3817,7 +3821,7 @@
         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
 
         int tag = TAG_UNDEFINED; // for use while saving state (the index)
-        long lastWidgetUpdateTime; // last time we were successfully able to send an update.
+        long lastWidgetUpdateRequestId; // request id for the last update successfully sent
 
         public int getUserId() {
             return UserHandle.getUserId(id.uid);
@@ -3844,18 +3848,18 @@
          */
         public boolean getPendingUpdatesForId(int appWidgetId,
                 LongSparseArray<PendingHostUpdate> outUpdates) {
-            long updateTime = lastWidgetUpdateTime;
+            long updateRequestId = lastWidgetUpdateRequestId;
             int N = widgets.size();
             for (int i = 0; i < N; i++) {
                 Widget widget = widgets.get(i);
                 if (widget.appWidgetId == appWidgetId) {
                     outUpdates.clear();
-                    for (int j = widget.updateTimes.size() - 1; j >= 0; j--) {
-                        long time = widget.updateTimes.valueAt(j);
-                        if (time <= updateTime) {
+                    for (int j = widget.updateRequestIds.size() - 1; j >= 0; j--) {
+                        long requestId = widget.updateRequestIds.valueAt(j);
+                        if (requestId <= updateRequestId) {
                             continue;
                         }
-                        int id = widget.updateTimes.keyAt(j);
+                        int id = widget.updateRequestIds.keyAt(j);
                         final PendingHostUpdate update;
                         switch (id) {
                             case ID_PROVIDER_CHANGED:
@@ -3869,7 +3873,7 @@
                             default:
                                 update = PendingHostUpdate.viewDataChanged(appWidgetId, id);
                         }
-                        outUpdates.put(time, update);
+                        outUpdates.put(requestId, update);
                     }
                     return true;
                 }
@@ -3951,8 +3955,8 @@
         RemoteViews maskedViews;
         Bundle options;
         Host host;
-        // timestamps for various operations
-        SparseLongArray updateTimes = new SparseLongArray(2);
+        // Request ids for various operations
+        SparseLongArray updateRequestIds = new SparseLongArray(2);
 
         @Override
         public String toString() {
diff --git a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
index 3de8a8b..ae21b07 100644
--- a/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutoFillManagerServiceImpl.java
@@ -202,7 +202,7 @@
 
         final AutoFillServiceInfo info;
         try {
-            info = new AutoFillServiceInfo(component, mUserId);
+            info = new AutoFillServiceInfo(context.getPackageManager(), component, mUserId);
         } catch (PackageManager.NameNotFoundException e) {
             Slog.w(TAG, "Auto-fill service not found: " + component, e);
             mInfo = null;
diff --git a/services/core/Android.mk b/services/core/Android.mk
index 1366b3b..cd88b85 100644
--- a/services/core/Android.mk
+++ b/services/core/Android.mk
@@ -24,7 +24,9 @@
     android.hardware.power@1.0-java \
     android.hardware.tv.cec@1.0-java
 
-LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update2
+LOCAL_STATIC_JAVA_LIBRARIES := tzdata_update2 \
+    android.hidl.base@1.0-java-static \
+    android.hardware.biometrics.fingerprint@2.1-java-static \
 
 ifneq ($(INCREMENTAL_BUILDS),)
     LOCAL_PROGUARD_ENABLED := disabled
diff --git a/services/core/java/com/android/server/DiskStatsService.java b/services/core/java/com/android/server/DiskStatsService.java
index dd95f67..962ac6f 100644
--- a/services/core/java/com/android/server/DiskStatsService.java
+++ b/services/core/java/com/android/server/DiskStatsService.java
@@ -95,9 +95,7 @@
             pw.println("File-based Encryption: true");
         }
 
-        if (isCheckin(args)) {
-            reportCachedValues(pw);
-        }
+        reportCachedValues(pw);
 
         // TODO: Read /proc/yaffs and report interesting values;
         // add configurable (through args) performance test parameters.
@@ -130,15 +128,6 @@
         }
     }
 
-    private boolean isCheckin(String[] args) {
-        for (String opt : args) {
-            if ("--checkin".equals(opt)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
     private void reportCachedValues(PrintWriter pw) {
         try {
             String jsonString = IoUtils.readFileAsString(DISKSTATS_DUMP_FILE);
diff --git a/services/core/java/com/android/server/NetworkScoreService.java b/services/core/java/com/android/server/NetworkScoreService.java
index e23844c..6f49702 100644
--- a/services/core/java/com/android/server/NetworkScoreService.java
+++ b/services/core/java/com/android/server/NetworkScoreService.java
@@ -42,15 +42,22 @@
 import android.net.ScoredNetwork;
 import android.net.Uri;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteCallback;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.Pair;
 import android.util.TimedRemoteCaller;
 
 import com.android.internal.annotations.GuardedBy;
@@ -67,6 +74,8 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeoutException;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
 
 /**
@@ -75,21 +84,24 @@
  */
 public class NetworkScoreService extends INetworkScoreService.Stub {
     private static final String TAG = "NetworkScoreService";
-    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean DBG = Build.IS_DEBUGGABLE && Log.isLoggable(TAG, Log.DEBUG);
 
     private final Context mContext;
     private final NetworkScorerAppManager mNetworkScorerAppManager;
-    private final RequestRecommendationCaller mRequestRecommendationCaller;
+    private final AtomicReference<RequestRecommendationCaller> mReqRecommendationCallerRef;
     @GuardedBy("mScoreCaches")
     private final Map<Integer, RemoteCallbackList<INetworkScoreCache>> mScoreCaches;
     /** Lock used to update mPackageMonitor when scorer package changes occur. */
-    private final Object mPackageMonitorLock = new Object[0];
-    private final Object mServiceConnectionLock = new Object[0];
+    private final Object mPackageMonitorLock = new Object();
+    private final Object mServiceConnectionLock = new Object();
+    private final Handler mHandler;
+    private final DispatchingContentObserver mContentObserver;
 
     @GuardedBy("mPackageMonitorLock")
     private NetworkScorerPackageMonitor mPackageMonitor;
     @GuardedBy("mServiceConnectionLock")
     private ScoringServiceConnection mServiceConnection;
+    private volatile long mRecommendationRequestTimeoutMs;
 
     private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
         @Override
@@ -185,12 +197,25 @@
     }
 
     /**
-     * Reevaluates the service binding when the Settings toggle is changed.
+     * Dispatches observed content changes to a handler for further processing.
      */
-    private class SettingsObserver extends ContentObserver {
+    @VisibleForTesting
+    public static class DispatchingContentObserver extends ContentObserver {
+        final private Map<Uri, Integer> mUriEventMap;
+        final private Context mContext;
+        final private Handler mHandler;
 
-        public SettingsObserver() {
-            super(null /*handler*/);
+        public DispatchingContentObserver(Context context, Handler handler) {
+            super(handler);
+            mContext = context;
+            mHandler = handler;
+            mUriEventMap = new ArrayMap<>();
+        }
+
+        void observe(Uri uri, int what) {
+            mUriEventMap.put(uri, what);
+            final ContentResolver resolver = mContext.getContentResolver();
+            resolver.registerContentObserver(uri, false /*notifyForDescendants*/, this);
         }
 
         @Override
@@ -201,16 +226,22 @@
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             if (DBG) Log.d(TAG, String.format("onChange(%s, %s)", selfChange, uri));
-            bindToScoringServiceIfNeeded();
+            final Integer what = mUriEventMap.get(uri);
+            if (what != null) {
+                mHandler.obtainMessage(what).sendToTarget();
+            } else {
+                Log.w(TAG, "No matching event to send for URI = " + uri);
+            }
         }
     }
 
     public NetworkScoreService(Context context) {
-      this(context, new NetworkScorerAppManager(context));
+      this(context, new NetworkScorerAppManager(context), Looper.myLooper());
     }
 
     @VisibleForTesting
-    NetworkScoreService(Context context, NetworkScorerAppManager networkScoreAppManager) {
+    NetworkScoreService(Context context, NetworkScorerAppManager networkScoreAppManager,
+            Looper looper) {
         mContext = context;
         mNetworkScorerAppManager = networkScoreAppManager;
         mScoreCaches = new ArrayMap<>();
@@ -219,16 +250,19 @@
         mContext.registerReceiverAsUser(
                 mUserIntentReceiver, UserHandle.SYSTEM, filter, null /* broadcastPermission*/,
                 null /* scheduler */);
-        // TODO(jjoslin): 12/15/16 - Make timeout configurable.
-        mRequestRecommendationCaller =
-            new RequestRecommendationCaller(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS);
+        mReqRecommendationCallerRef = new AtomicReference<>(
+                new RequestRecommendationCaller(TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS));
+        mRecommendationRequestTimeoutMs = TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS;
+        mHandler = new ServiceHandler(looper);
+        mContentObserver = new DispatchingContentObserver(context, mHandler);
     }
 
     /** Called when the system is ready to run third-party code but before it actually does so. */
     void systemReady() {
         if (DBG) Log.d(TAG, "systemReady");
         registerPackageMonitorIfNeeded();
-        registerRecommendationSettingObserverIfNeeded();
+        registerRecommendationSettingsObserver();
+        refreshRecommendationRequestTimeoutMs();
     }
 
     /** Called when the system is ready for us to start third-party code. */
@@ -242,14 +276,18 @@
         bindToScoringServiceIfNeeded();
     }
 
-    private void registerRecommendationSettingObserverIfNeeded() {
+    private void registerRecommendationSettingsObserver() {
         final List<String> providerPackages =
             mNetworkScorerAppManager.getPotentialRecommendationProviderPackages();
         if (!providerPackages.isEmpty()) {
-            final ContentResolver resolver = mContext.getContentResolver();
-            final Uri uri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_ENABLED);
-            resolver.registerContentObserver(uri, false, new SettingsObserver());
+            final Uri enabledUri = Global.getUriFor(Global.NETWORK_RECOMMENDATIONS_ENABLED);
+            mContentObserver.observe(enabledUri,
+                    ServiceHandler.MSG_RECOMMENDATIONS_ENABLED_CHANGED);
         }
+
+        final Uri timeoutUri = Global.getUriFor(Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS);
+        mContentObserver.observe(timeoutUri,
+                ServiceHandler.MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED);
     }
 
     private void registerPackageMonitorIfNeeded() {
@@ -532,7 +570,8 @@
             final INetworkRecommendationProvider provider = getRecommendationProvider();
             if (provider != null) {
                 try {
-                    return mRequestRecommendationCaller.getRecommendationResult(provider, request);
+                    final RequestRecommendationCaller caller = mReqRecommendationCallerRef.get();
+                    return caller.getRecommendationResult(provider, request);
                 } catch (RemoteException | TimeoutException e) {
                     Log.w(TAG, "Failed to request a recommendation.", e);
                     // TODO(jjoslin): 12/15/16 - Keep track of failures.
@@ -553,6 +592,56 @@
         }
     }
 
+    /**
+     * Request a recommendation for the best network to connect to
+     * taking into account the inputs from the {@link RecommendationRequest}.
+     *
+     * @param request a {@link RecommendationRequest} instance containing the details of the request
+     * @param remoteCallback a {@link IRemoteCallback} instance to invoke when the recommendation
+     *                       is available.
+     * @throws SecurityException if the caller is not the system
+     */
+    @Override
+    public void requestRecommendationAsync(RecommendationRequest request,
+            RemoteCallback remoteCallback) {
+        mContext.enforceCallingOrSelfPermission(permission.BROADCAST_NETWORK_PRIVILEGED, TAG);
+
+        final OneTimeCallback oneTimeCallback = new OneTimeCallback(remoteCallback);
+        final Pair<RecommendationRequest, OneTimeCallback> pair =
+                Pair.create(request, oneTimeCallback);
+        final Message timeoutMsg = mHandler.obtainMessage(
+                ServiceHandler.MSG_RECOMMENDATION_REQUEST_TIMEOUT, pair);
+        final INetworkRecommendationProvider provider = getRecommendationProvider();
+        final long token = Binder.clearCallingIdentity();
+        try {
+            if (provider != null) {
+                try {
+                    mHandler.sendMessageDelayed(timeoutMsg, mRecommendationRequestTimeoutMs);
+                    provider.requestRecommendation(request, new IRemoteCallback.Stub() {
+                        @Override
+                        public void sendResult(Bundle data) throws RemoteException {
+                            // Remove the timeout message
+                            mHandler.removeMessages(timeoutMsg.what, pair);
+                            oneTimeCallback.sendResult(data);
+                        }
+                    }, 0 /*sequence*/);
+                    return;
+                } catch (RemoteException e) {
+                    Log.w(TAG, "Failed to request a recommendation.", e);
+                    // TODO(jjoslin): 12/15/16 - Keep track of failures.
+                    // Remove the timeout message
+                    mHandler.removeMessages(timeoutMsg.what, pair);
+                    // Will fall through and send back the default recommendation.
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+
+        // Else send back the default recommendation.
+        sendDefaultRecommendationResponse(request, oneTimeCallback);
+    }
+
     @Override
     public boolean requestScores(NetworkKey[] networks) {
         mContext.enforceCallingOrSelfPermission(permission.REQUEST_NETWORK_SCORES, TAG);
@@ -651,6 +740,19 @@
         return null;
     }
 
+    @VisibleForTesting
+    public void refreshRecommendationRequestTimeoutMs() {
+        final ContentResolver cr = mContext.getContentResolver();
+        long timeoutMs = Settings.Global.getLong(cr,
+                Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, -1L /*default*/);
+        if (timeoutMs < 0) {
+            timeoutMs = TimedRemoteCaller.DEFAULT_CALL_TIMEOUT_MILLIS;
+        }
+        if (DBG) Log.d(TAG, "Updating the recommendation request timeout to " + timeoutMs + " ms");
+        mRecommendationRequestTimeoutMs = timeoutMs;
+        mReqRecommendationCallerRef.set(new RequestRecommendationCaller(timeoutMs));
+    }
+
     private static class ScoringServiceConnection implements ServiceConnection {
         private final ComponentName mComponentName;
         private final int mScoringAppUid;
@@ -756,4 +858,83 @@
             return getResultTimed(sequence);
         }
     }
+
+    /**
+     * A wrapper around {@link RemoteCallback} that guarantees
+     * {@link RemoteCallback#sendResult(Bundle)} will be invoked at most once.
+     */
+    @VisibleForTesting
+    public static final class OneTimeCallback {
+        private final RemoteCallback mRemoteCallback;
+        private final AtomicBoolean mCallbackRun;
+
+        public OneTimeCallback(RemoteCallback remoteCallback) {
+            mRemoteCallback = remoteCallback;
+            mCallbackRun = new AtomicBoolean(false);
+        }
+
+        public void sendResult(Bundle data) {
+            if (mCallbackRun.compareAndSet(false, true)) {
+                mRemoteCallback.sendResult(data);
+            }
+        }
+    }
+
+    private static void sendDefaultRecommendationResponse(RecommendationRequest request,
+            OneTimeCallback remoteCallback) {
+        if (DBG) {
+            Log.d(TAG, "Returning the default network recommendation.");
+        }
+
+        final RecommendationResult result;
+        if (request != null && request.getCurrentSelectedConfig() != null) {
+            result = RecommendationResult.createConnectRecommendation(
+                    request.getCurrentSelectedConfig());
+        } else {
+            result = RecommendationResult.createDoNotConnectRecommendation();
+        }
+
+        final Bundle data = new Bundle();
+        data.putParcelable(EXTRA_RECOMMENDATION_RESULT, result);
+        remoteCallback.sendResult(data);
+    }
+
+    @VisibleForTesting
+    public final class ServiceHandler extends Handler {
+        public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT = 1;
+        public static final int MSG_RECOMMENDATIONS_ENABLED_CHANGED = 2;
+        public static final int MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED = 3;
+
+        public ServiceHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            final int what = msg.what;
+            switch (what) {
+                case MSG_RECOMMENDATION_REQUEST_TIMEOUT:
+                    if (DBG) {
+                        Log.d(TAG, "Network recommendation request timed out.");
+                    }
+                    final Pair<RecommendationRequest, OneTimeCallback> pair =
+                            (Pair<RecommendationRequest, OneTimeCallback>) msg.obj;
+                    final RecommendationRequest request = pair.first;
+                    final OneTimeCallback remoteCallback = pair.second;
+                    sendDefaultRecommendationResponse(request, remoteCallback);
+                    break;
+
+                case MSG_RECOMMENDATIONS_ENABLED_CHANGED:
+                    bindToScoringServiceIfNeeded();
+                    break;
+
+                case MSG_RECOMMENDATION_REQUEST_TIMEOUT_CHANGED:
+                    refreshRecommendationRequestTimeoutMs();
+                    break;
+
+                default:
+                    Log.w(TAG,"Unknown message: " + what);
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/RecoverySystemService.java b/services/core/java/com/android/server/RecoverySystemService.java
index 2010e64..3c8c699 100644
--- a/services/core/java/com/android/server/RecoverySystemService.java
+++ b/services/core/java/com/android/server/RecoverySystemService.java
@@ -181,7 +181,7 @@
         }
 
         @Override // Binder call
-        public void rebootRecoveryWithCommand(String command, boolean update) {
+        public void rebootRecoveryWithCommand(String command) {
             if (DEBUG) Slog.d(TAG, "rebootRecoveryWithCommand: [" + command + "]");
             synchronized (sRequestLock) {
                 if (!setupOrClearBcb(true, command)) {
@@ -190,10 +190,7 @@
 
                 // Having set up the BCB, go ahead and reboot.
                 PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-                // PowerManagerService may additionally request uncrypting the package when it's
-                // to install an update (REBOOT_RECOVERY_UPDATE).
-                pm.reboot(update ? PowerManager.REBOOT_RECOVERY_UPDATE :
-                        PowerManager.REBOOT_RECOVERY);
+                pm.reboot(PowerManager.REBOOT_RECOVERY);
             }
         }
 
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 55d31c3..f9b9d6f 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -88,11 +88,13 @@
 import android.util.Log;
 import android.util.Pair;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.util.Xml;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IMediaContainerService;
+import com.android.internal.os.AppFuseMount;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.os.Zygote;
 import com.android.internal.util.ArrayUtils;
@@ -104,7 +106,7 @@
 import com.android.server.NativeDaemonConnector.Command;
 import com.android.server.NativeDaemonConnector.SensitiveArg;
 import com.android.server.pm.PackageManagerService;
-
+import com.android.server.storage.AppFuseBridge;
 import libcore.io.IoUtils;
 import libcore.util.EmptyArray;
 
@@ -135,6 +137,7 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
@@ -337,6 +340,15 @@
 
     private volatile int mCurrentUserId = UserHandle.USER_SYSTEM;
 
+    /** Holding lock for AppFuse business */
+    private final Object mAppFuseLock = new Object();
+
+    @GuardedBy("mAppFuseLock")
+    private int mNextAppFuseName = 0;
+
+    @GuardedBy("mAppFuseLock")
+    private final SparseArray<Integer> mAppFusePids = new SparseArray<>();
+
     private VolumeInfo findVolumeByIdOrThrow(String id) {
         synchronized (mLock) {
             final VolumeInfo vol = mVolumes.get(id);
@@ -3010,6 +3022,128 @@
         }
     }
 
+
+    class CloseableHolder<T extends AutoCloseable> implements AutoCloseable {
+        @Nullable T mCloseable;
+
+        CloseableHolder(T closeable) {
+            mCloseable = closeable;
+        }
+
+        @Nullable T get() {
+            return mCloseable;
+        }
+
+        @Nullable T release() {
+            final T result = mCloseable;
+            mCloseable = null;
+            return result;
+        }
+
+        @Override
+        public void close() {
+            if (mCloseable != null) {
+                IoUtils.closeQuietly(mCloseable);
+            }
+        }
+    }
+
+    class AppFuseMountScope implements AppFuseBridge.IMountScope {
+        final int mUid;
+        final int mName;
+        final ParcelFileDescriptor mDeviceFd;
+
+        AppFuseMountScope(int uid, int pid, int name) throws NativeDaemonConnectorException {
+            final NativeDaemonEvent event = mConnector.execute(
+                    "appfuse", "mount", uid, Process.myPid(), name);
+            mUid = uid;
+            mName = name;
+            synchronized (mLock) {
+                mAppFusePids.put(name, pid);
+            }
+            if (event.getFileDescriptors() != null &&
+                    event.getFileDescriptors().length > 0) {
+                mDeviceFd = new ParcelFileDescriptor(event.getFileDescriptors()[0]);
+            } else {
+                mDeviceFd = null;
+            }
+        }
+
+        @Override
+        public void close() throws NativeDaemonConnectorException {
+            try {
+                IoUtils.closeQuietly(mDeviceFd);
+                mConnector.execute(
+                        "appfuse", "unmount", mUid, Process.myPid(), mName);
+            } finally {
+                synchronized (mLock) {
+                    mAppFusePids.delete(mName);
+                }
+            }
+        }
+
+        @Override
+        public ParcelFileDescriptor getDeviceFileDescriptor() {
+            return mDeviceFd;
+        }
+    }
+
+    @Override
+    public AppFuseMount mountProxyFileDescriptorBridge() throws RemoteException {
+        final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
+        final int name;
+        synchronized (mAppFuseLock) {
+            name = mNextAppFuseName++;
+        }
+        try (CloseableHolder<AppFuseMountScope> mountScope =
+                new CloseableHolder<>(new AppFuseMountScope(uid, pid, name))) {
+            if (mountScope.get().getDeviceFileDescriptor() == null) {
+                throw new RemoteException("Failed to obtain device FD");
+            }
+
+            // Create communication channel.
+            final ArrayBlockingQueue<Boolean> channel = new ArrayBlockingQueue<>(1);
+            final ParcelFileDescriptor[] fds = ParcelFileDescriptor.createSocketPair();
+            try (CloseableHolder<ParcelFileDescriptor> remote = new CloseableHolder<>(fds[0])) {
+                new Thread(
+                        new AppFuseBridge(mountScope.release(), fds[1], channel),
+                        AppFuseBridge.TAG).start();
+                if (!channel.take()) {
+                    throw new RemoteException("Failed to init AppFuse mount point");
+                }
+
+                return new AppFuseMount(name, remote.release());
+            }
+        } catch (NativeDaemonConnectorException e){
+            throw e.rethrowAsParcelableException();
+        } catch (IOException | InterruptedException error) {
+            throw new RemoteException(error.getMessage());
+        }
+    }
+
+    @Override
+    public ParcelFileDescriptor openProxyFileDescriptor(int mountId, int fileId, int mode) {
+        final int uid = Binder.getCallingUid();
+        final int pid = Binder.getCallingPid();
+        try {
+            synchronized (mAppFuseLock) {
+                final int expectedPid = mAppFusePids.get(mountId, -1);
+                if (expectedPid == -1) {
+                    Slog.i(TAG, "The mount point has already been unmounted");
+                    return null;
+                }
+                if (expectedPid != pid) {
+                    throw new SecurityException("Mount point was not created by this process.");
+                }
+            }
+            return AppFuseBridge.openFile(uid, mountId, fileId, mode);
+        } catch (FileNotFoundException error) {
+            Slog.e(TAG, "Failed to openProxyFileDescriptor", error);
+            return null;
+        }
+    }
+
     @Override
     public int mkdirs(String callingPkg, String appPath) {
         final int userId = UserHandle.getUserId(Binder.getCallingUid());
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c87412e..7fd91cb 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -9572,7 +9572,7 @@
                 boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0;
                 if (stackId != task.getStackId()) {
                     mStackSupervisor.moveTaskToStackUncheckedLocked(task, stackId, ON_TOP,
-                            !FORCE_FOCUS, "resizeTask", true /* allowStackOnTop */);
+                            !FORCE_FOCUS, "resizeTask");
                     preserveWindow = false;
                 }
 
@@ -10020,7 +10020,7 @@
                 // Defer the resume so resume/pausing while moving stacks is dangerous.
                 mStackSupervisor.moveTaskToStackLocked(topTask.taskId, DOCKED_STACK_ID,
                         false /* toTop */, !FORCE_FOCUS, "swapDockedAndFullscreenStack",
-                        ANIMATE, true /* deferResume */, true /* allowStackOnTop */);
+                        ANIMATE, true /* deferResume */);
                 final int size = tasks.size();
                 for (int i = 0; i < size; i++) {
                     final int id = tasks.get(i).taskId;
@@ -10029,8 +10029,7 @@
                     }
                     mStackSupervisor.moveTaskToStackLocked(id,
                             FULLSCREEN_WORKSPACE_STACK_ID, true /* toTop */, !FORCE_FOCUS,
-                            "swapDockedAndFullscreenStack", ANIMATE, true /* deferResume */,
-                            true /* allowStackOnTop */);
+                            "swapDockedAndFullscreenStack", ANIMATE, true /* deferResume */);
                 }
 
                 // Because we deferred the resume, to avoid conflicts with stack switches while
@@ -10071,7 +10070,7 @@
                 mWindowManager.setDockedStackCreateState(createMode, initialBounds);
                 final boolean moved = mStackSupervisor.moveTaskToStackLocked(
                         taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS, "moveTaskToDockedStack",
-                        animate, DEFER_RESUME, true /* allowStackOnTop */);
+                        animate, DEFER_RESUME);
                 if (moved) {
                     if (moveHomeStackFront) {
                         mStackSupervisor.moveHomeStackToFront("moveTaskToDockedStack");
@@ -10187,10 +10186,24 @@
             try {
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "positionTaskInStack: positioning task="
                         + taskId + " in stackId=" + stackId + " at position=" + position);
+                final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+                if (task == null) {
+                    throw new IllegalArgumentException("positionTaskInStack: no task for id="
+                            + taskId);
+                }
+
                 final ActivityStack stack = mStackSupervisor.getStack(stackId, CREATE_IF_NEEDED,
                         !ON_TOP);
 
-                stack.positionChildAt(taskId, position);
+                // TODO: Have the callers of this API call a separate reparent method if that is
+                // what they intended to do vs. having this method also do reparenting.
+                if (task.getStack() == stack) {
+                    // Change position in current stack.
+                    stack.positionChildAt(task, position);
+                } else {
+                    // Reparent to new stack.
+                    task.reparent(stackId, position, "positionTaskInStack");
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 47c3e6f..a2fb9f9 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -1802,6 +1802,9 @@
     }
 
     void showStartingWindow(ActivityRecord prev, boolean newTask, boolean taskSwitch) {
+        if (mWindowContainerController == null) {
+            return;
+        }
         final CompatibilityInfo compatInfo =
                 service.compatibilityInfoForPackageLocked(info.applicationInfo);
         final boolean shown = mWindowContainerController.addStartingWindow(packageName, theme,
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index abcaa24..4df0cb1 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -72,6 +72,8 @@
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_OPEN_BEHIND;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_BACK;
 import static com.android.server.wm.AppTransition.TRANSIT_TASK_TO_FRONT;
+import static java.lang.Integer.MAX_VALUE;
+import static java.lang.Integer.MIN_VALUE;
 
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -2534,6 +2536,30 @@
         return null;
     }
 
+    /** Returns the position the input task should be placed in this stack. */
+    int getAdjustedPositionForTask(TaskRecord task, int suggestedPosition,
+            ActivityRecord starting) {
+
+        int maxPosition = mTaskHistory.size();
+        if ((starting != null && starting.okToShowLocked())
+                || (starting == null && task.okToShowLocked())) {
+            // If the task or starting activity can be shown, then whatever position is okay.
+            return Math.min(suggestedPosition, maxPosition);
+        }
+
+        // The task can't be shown, put non-current user tasks below current user tasks.
+        while (maxPosition > 0) {
+            final TaskRecord tmpTask = mTaskHistory.get(maxPosition - 1);
+            if (!mStackSupervisor.isCurrentProfileLocked(tmpTask.userId)
+                    || tmpTask.topRunningActivityLocked() == null) {
+                break;
+            }
+            maxPosition--;
+        }
+
+        return  Math.min(suggestedPosition, maxPosition);
+    }
+
     /**
      * Used from {@link ActivityStack#positionTask(TaskRecord, int)}.
      * @see ActivityManagerService#positionTaskInStack(int, int, int).
@@ -2543,32 +2569,25 @@
             insertTaskAtTop(task, null);
             return;
         }
-        // Calculate maximum possible position for this task.
-        int maxPosition = mTaskHistory.size();
-        if (!task.okToShowLocked()) {
-            // Put non-current user tasks below current user tasks.
-            while (maxPosition > 0) {
-                final TaskRecord tmpTask = mTaskHistory.get(maxPosition - 1);
-                if (!mStackSupervisor.isCurrentProfileLocked(tmpTask.userId)
-                        || tmpTask.topRunningActivityLocked() == null) {
-                    break;
-                }
-                maxPosition--;
-            }
-        }
-        position = Math.min(position, maxPosition);
+        position = getAdjustedPositionForTask(task, position, null /* starting */);
         mTaskHistory.remove(task);
         mTaskHistory.add(position, task);
-        task.positionWindowContainerAt(mStackId, position);
+        task.positionWindowContainerAt(position);
         updateTaskMovement(task, true);
     }
 
-    private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity) {
-        insertTaskAtTop(task, newActivity, true /* allowStackOnTop */);
+    private void insertTaskAtTop(TaskRecord task, ActivityRecord starting) {
+        updateTaskReturnToForTopInsertion(task);
+        // TODO: Better place to put all the code below...may be addTask...
+        mTaskHistory.remove(task);
+        // Now put task at top.
+        final int position = getAdjustedPositionForTask(task, mTaskHistory.size(), starting);
+        mTaskHistory.add(position, task);
+        updateTaskMovement(task, true);
+        task.moveWindowContainerToTop(true /* includingParents */);
     }
 
-    private void insertTaskAtTop(TaskRecord task, ActivityRecord newActivity,
-            boolean allowStackOnTop) {
+    private void updateTaskReturnToForTopInsertion(TaskRecord task) {
         boolean isLastTaskOverHome = false;
         // If the moving task is over home stack, transfer its return type to next task
         if (task.isOverHomeStack()) {
@@ -2585,49 +2604,27 @@
         if (isOnHomeDisplay()) {
             ActivityStack lastStack = mStackSupervisor.getLastStack();
             final boolean fromHomeOrRecents = lastStack.isHomeOrRecentsStack();
-            final boolean fromOnTopLauncher = lastStack.topTask() != null &&
-                    lastStack.topTask().isOnTopLauncher();
+            final TaskRecord topTask = lastStack.topTask();
+            final boolean fromOnTopLauncher = topTask != null && topTask.isOnTopLauncher();
             if (fromOnTopLauncher) {
                 // Since an on-top launcher will is moved to back when tasks are launched from it,
                 // those tasks should first try to return to a non-home activity.
                 // This also makes sure that non-home activities are visible under a transparent
                 // non-home activity.
                 task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
-            } else if (!isHomeOrRecentsStack() && (fromHomeOrRecents || topTask() != task)) {
+            } else if (!isHomeOrRecentsStack() && (fromHomeOrRecents || topTask != task)) {
                 // If it's a last task over home - we default to keep its return to type not to
                 // make underlying task focused when this one will be finished.
                 int returnToType = isLastTaskOverHome
                         ? task.getTaskToReturnTo() : APPLICATION_ACTIVITY_TYPE;
                 if (fromHomeOrRecents && StackId.allowTopTaskToReturnHome(mStackId)) {
-                    returnToType = lastStack.topTask() == null
-                            ? HOME_ACTIVITY_TYPE : lastStack.topTask().taskType;
+                    returnToType = topTask == null ? HOME_ACTIVITY_TYPE : topTask.taskType;
                 }
                 task.setTaskToReturnTo(returnToType);
             }
         } else {
             task.setTaskToReturnTo(APPLICATION_ACTIVITY_TYPE);
         }
-
-        mTaskHistory.remove(task);
-        // Now put task at top.
-        int taskNdx = mTaskHistory.size();
-        final boolean notShownWhenLocked =
-                (newActivity != null && !newActivity.okToShowLocked())
-                || (newActivity == null && !task.okToShowLocked());
-        if (notShownWhenLocked) {
-            // Put non-current user tasks below current user tasks.
-            while (--taskNdx >= 0) {
-                final TaskRecord tmpTask = mTaskHistory.get(taskNdx);
-                if (!mStackSupervisor.isCurrentProfileLocked(tmpTask.userId)
-                        || tmpTask.topRunningActivityLocked() == null) {
-                    break;
-                }
-            }
-            ++taskNdx;
-        }
-        mTaskHistory.add(taskNdx, task);
-        updateTaskMovement(task, true);
-        task.moveWindowContainerToTop(allowStackOnTop /* includingParents */);
     }
 
     final void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity,
@@ -4891,38 +4888,49 @@
     }
 
     void addTask(final TaskRecord task, final boolean toTop, String reason) {
-        addTask(task, toTop, reason, true /* allowStackOnTop */);
+        addTask(task, toTop ? MAX_VALUE : 0, reason);
+        if (toTop) {
+            // TODO: figure-out a way to remove this call.
+            task.moveWindowContainerToTop(true /* includingParents */);
+        }
     }
 
-    void addTask(final TaskRecord task, final boolean toTop, String reason,
-            boolean allowStackOnTop) {
+    // TODO: This shouldn't allow automatic reparenting. Remove the call to preAddTask and deal
+    // with the fall-out...
+    void addTask(final TaskRecord task, int position, String reason) {
+        // TODO: Is this remove really needed? Need to look into the call path for the other addTask
+        mTaskHistory.remove(task);
+        position = getAdjustedPositionForTask(task, position, null /* starting */);
+        final boolean toTop = position >= mTaskHistory.size();
         final ActivityStack prevStack = preAddTask(task, reason, toTop);
 
         task.setStack(this);
+
         if (toTop) {
-            insertTaskAtTop(task, null, allowStackOnTop);
-        } else {
-            mTaskHistory.add(0, task);
-            updateTaskMovement(task, false);
+            updateTaskReturnToForTopInsertion(task);
         }
+
+        mTaskHistory.add(position, task);
+        updateTaskMovement(task, toTop);
+
         postAddTask(task, prevStack);
     }
 
-    void positionChildAt(int taskId, int index) {
-        final TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
-        if (task == null) {
-            Slog.w(TAG, "positionTaskInStackLocked: no task for id=" + taskId);
-            return;
+    void positionChildAt(TaskRecord task, int index) {
+
+        if (task.getStack() != this) {
+            throw new IllegalArgumentException("AS.positionChildAt: task=" + task
+                    + " is not a child of stack=" + this + " current parent=" + task.getStack());
         }
 
         task.updateOverrideConfigurationForStack(this);
 
         final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
         final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
-        final ActivityStack prevStack = preAddTask(task, "positionTask", !ON_TOP);
         task.setStack(this);
         insertTaskAtPosition(task, index);
-        postAddTask(task, prevStack);
+        postAddTask(task, null /* prevStack */);
+
         if (wasResumed) {
             if (mResumedActivity != null) {
                 Log.wtf(TAG, "mResumedActivity was already set when moving mResumedActivity from"
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8cf0708..4fe8939 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -1933,7 +1933,7 @@
                 }
                 if (stackId != currentStack.mStackId) {
                     currentStack = moveTaskToStackUncheckedLocked(task, stackId, ON_TOP,
-                            !FORCE_FOCUS, reason, true /* allowStackOnTop */);
+                            !FORCE_FOCUS, reason);
                     stackId = currentStack.mStackId;
                     // moveTaskToStackUncheckedLocked() should already placed the task on top,
                     // still need moveTaskToFrontLocked() below for any transition settings.
@@ -1984,7 +1984,6 @@
         if (!createStaticStackIfNeeded || !StackId.isStaticStack(stackId)) {
             return null;
         }
-        // TODO(multi-display): Allow creating stacks on secondary displays.
         return createStackOnDisplay(stackId, DEFAULT_DISPLAY, createOnTop);
     }
 
@@ -2238,18 +2237,16 @@
                     }
                     moveTaskToStackLocked(tasks.get(i).taskId,
                             FULLSCREEN_WORKSPACE_STACK_ID, onTop, onTop /*forceFocus*/,
-                            "moveTasksToFullscreenStack - onTop", ANIMATE, DEFER_RESUME,
-                            true /* allowStackOnTop */);
+                            "moveTasksToFullscreenStack - onTop", ANIMATE, DEFER_RESUME);
                 }
 
                 ensureActivitiesVisibleLocked(null, 0, PRESERVE_WINDOWS);
                 resumeFocusedStackTopActivityLocked();
             } else {
                 for (int i = 0; i < size; i++) {
-                    moveTaskToStackLocked(tasks.get(i).taskId, FULLSCREEN_WORKSPACE_STACK_ID,
-                            true /* onTop */, false /* forceFocus */,
-                            "moveTasksToFullscreenStack - NOT_onTop", !ANIMATE, DEFER_RESUME,
-                            false /* allowStackOnTop */);
+                    final TaskRecord task = tasks.get(i);
+                    task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, MAX_VALUE,
+                            "moveTasksToFullscreenStack - NOT_onTop");
                 }
             }
         } finally {
@@ -2385,7 +2382,8 @@
                     final int insertPosition = isFullscreenStackVisible
                             ? Math.max(0, fullscreenStack.getChildCount() - 1)
                             : fullscreenStack.getChildCount();
-                    fullscreenStack.positionChildAt(tasks.get(i).taskId, insertPosition);
+                    final TaskRecord task = tasks.get(i);
+                    task.reparent(FULLSCREEN_WORKSPACE_STACK_ID, insertPosition, "removeStack");
                 }
                 ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 resumeFocusedStackTopActivityLocked();
@@ -2605,13 +2603,10 @@
      * @param toTop True if the task should be placed at the top of the stack.
      * @param forceFocus if focus should be moved to the new stack
      * @param reason Reason the task is been moved.
-     * @param allowStackOnTop If stack movement should be moved to the top due to the addition of
-     *                        the task to the stack. E.g. Moving the stack to the front because it
-     *                        should be focused because it now contains the focused activity.
      * @return The stack the task was moved to.
      */
     ActivityStack moveTaskToStackUncheckedLocked(TaskRecord task, int stackId, boolean toTop,
-            boolean forceFocus, String reason, boolean allowStackOnTop) {
+            boolean forceFocus, String reason) {
 
         if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) {
             throw new IllegalStateException("moveTaskToStackUncheckedLocked: Device doesn't "
@@ -2642,15 +2637,14 @@
         // if a docked stack is created below which will lead to the stack we are moving from and
         // its resizeable tasks being resized.
         task.mTemporarilyUnresizable = true;
-        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop && allowStackOnTop);
+        final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
         task.mTemporarilyUnresizable = false;
-        task.reparentWindowContainer(stack.mStackId, toTop ? MAX_VALUE : MIN_VALUE);
-        stack.addTask(task, toTop, reason, allowStackOnTop);
+        task.reparent(stack.mStackId, toTop ? MAX_VALUE : 0, reason);
 
         // If the task had focus before (or we're requested to move focus),
         // move focus to the new stack by moving the stack to the front.
         stack.moveToFrontAndResumeStateIfNeeded(
-                r, allowStackOnTop && (forceFocus || wasFocused || wasFront), wasResumed, reason);
+                r, forceFocus || wasFocused || wasFront, wasResumed, reason);
 
         return stack;
     }
@@ -2658,11 +2652,11 @@
     boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
             String reason, boolean animate) {
         return moveTaskToStackLocked(taskId, stackId, toTop, forceFocus, reason, animate,
-                false /* deferResume */, true /* allowStackOnTop */);
+                false /* deferResume */);
     }
 
     boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
-            String reason, boolean animate, boolean deferResume, boolean allowStackOnTop) {
+            String reason, boolean animate, boolean deferResume) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
             Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
@@ -2702,7 +2696,7 @@
         boolean kept = true;
         try {
             final ActivityStack stack = moveTaskToStackUncheckedLocked(
-                    task, stackId, toTop, forceFocus, reason + " moveTaskToStack", allowStackOnTop);
+                    task, stackId, toTop, forceFocus, reason + " moveTaskToStack");
             stackId = stack.mStackId;
 
             if (!animate) {
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 547e0b2..2634385 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -32,7 +32,7 @@
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.ActivityManager.StackId.RECENTS_STACK_ID;
-import static android.app.ActivityManager.StackId.isStaticStack;
+import static android.app.ActivityManager.StackId.isDynamicStack;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
 import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
@@ -1777,7 +1777,7 @@
             int stackId = mInTask.getLaunchStackId();
             if (stackId != mInTask.getStackId()) {
                 final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(mInTask,
-                        stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront", true /* allowStackOnTop */);
+                        stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
                 stackId = stack.mStackId;
             }
             if (StackId.resizeStackWithLaunchBounds(stackId)) {
@@ -1926,7 +1926,7 @@
         final boolean canUseFocusedStack = focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
                 || (focusedStackId == DOCKED_STACK_ID && r.canGoInDockedStack())
                 || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeableOrForced())
-                || !isStaticStack(focusedStackId);
+                || isDynamicStack(focusedStackId);
         if (canUseFocusedStack && (!newTask
                 || mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
             if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
@@ -1938,7 +1938,7 @@
         final ArrayList<ActivityStack> homeDisplayStacks = mSupervisor.mHomeStack.mStacks;
         for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             stack = homeDisplayStacks.get(stackNdx);
-            if (!ActivityManager.StackId.isStaticStack(stack.mStackId)) {
+            if (isDynamicStack(stack.mStackId)) {
                 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
                         "computeStackFocus: Setting focused stack=" + stack);
                 return stack;
diff --git a/services/core/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java
index e2870d8..9348023 100644
--- a/services/core/java/com/android/server/am/NativeCrashListener.java
+++ b/services/core/java/com/android/server/am/NativeCrashListener.java
@@ -20,7 +20,6 @@
 import android.system.ErrnoException;
 import android.system.Os;
 import android.system.StructTimeval;
-import android.system.StructUcred;
 import android.system.UnixSocketAddress;
 import android.util.Slog;
 
@@ -105,9 +104,9 @@
 
         if (DEBUG) Slog.i(TAG, "Starting up");
 
-        // The file system entity for this socket is created with 0700 perms, owned
-        // by system:system.  debuggerd runs as root, so is capable of connecting to
-        // it, but 3rd party apps cannot.
+        // The file system entity for this socket is created with 0777 perms, owned
+        // by system:system. selinux restricts things so that only crash_dump can
+        // access it.
         {
             File socketFile = new File(DEBUGGERD_SOCKET_PATH);
             if (socketFile.exists()) {
@@ -121,6 +120,7 @@
                     DEBUGGERD_SOCKET_PATH);
             Os.bind(serverFd, sockAddr);
             Os.listen(serverFd, 1);
+            Os.chmod(DEBUGGERD_SOCKET_PATH, 0777);
 
             while (true) {
                 FileDescriptor peerFd = null;
@@ -129,19 +129,14 @@
                     peerFd = Os.accept(serverFd, null /* peerAddress */);
                     if (MORE_DEBUG) Slog.v(TAG, "Got debuggerd socket " + peerFd);
                     if (peerFd != null) {
-                        // Only the superuser is allowed to talk to us over this socket
-                        StructUcred credentials =
-                                Os.getsockoptUcred(peerFd, SOL_SOCKET, SO_PEERCRED);
-                        if (credentials.uid == 0) {
-                            // the reporting thread may take responsibility for
-                            // acking the debugger; make sure we play along.
-                            consumeNativeCrashData(peerFd);
-                        }
+                        // the reporting thread may take responsibility for
+                        // acking the debugger; make sure we play along.
+                        consumeNativeCrashData(peerFd);
                     }
                 } catch (Exception e) {
                     Slog.w(TAG, "Error handling connection", e);
                 } finally {
-                    // Always ack debuggerd's connection to us.  The actual
+                    // Always ack crash_dump's connection to us.  The actual
                     // byte written is irrelevant.
                     if (peerFd != null) {
                         try {
@@ -194,7 +189,7 @@
         return totalRead;
     }
 
-    // Read the crash report from the debuggerd connection
+    // Read a crash report from the connection
     void consumeNativeCrashData(FileDescriptor fd) {
         if (MORE_DEBUG) Slog.i(TAG, "debuggerd connected");
         final byte[] buf = new byte[4096];
@@ -205,6 +200,10 @@
             Os.setsockoptTimeval(fd, SOL_SOCKET, SO_RCVTIMEO, timeout);
             Os.setsockoptTimeval(fd, SOL_SOCKET, SO_SNDTIMEO, timeout);
 
+            // The socket is guarded by an selinux neverallow rule that only
+            // permits crash_dump to connect to it. This allows us to trust the
+            // received values.
+
             // first, the pid and signal number
             int headerBytes = readExactly(fd, buf, 0, 8);
             if (headerBytes != 8) {
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index cb20eac..d035fa9 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -16,6 +16,8 @@
 
 package com.android.server.am;
 
+import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
 import android.app.ITaskStackListener;
 import android.app.ActivityManager.TaskDescription;
 import android.content.ComponentName;
@@ -43,6 +45,7 @@
     static final int NOTIFY_ACTIVITY_REQUESTED_ORIENTATION_CHANGED_LISTENERS = 12;
     static final int NOTIFY_TASK_REMOVAL_STARTED_LISTENERS = 13;
     static final int NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG = 14;
+    static final int NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG = 15;
 
     // Delay in notifying task stack change listeners (in millis)
     static final int NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY = 100;
@@ -113,6 +116,10 @@
         l.onTaskProfileLocked(m.arg1, m.arg2);
     };
 
+    private final TaskStackConsumer mNotifyTaskSnapshotChanged = (l, m) -> {
+        l.onTaskSnapshotChanged(m.arg1, (TaskSnapshot) m.obj);
+    };
+
     @FunctionalInterface
     public interface TaskStackConsumer {
         void accept(ITaskStackListener t, Message m) throws RemoteException;
@@ -170,7 +177,9 @@
                     break;
                 case NOTIFY_TASK_PROFILE_LOCKED_LISTENERS_MSG:
                     forAllRemoteListeners(mNotifyTaskProfileLocked, msg);
-
+                    break;
+                case NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG:
+                    forAllRemoteListeners(mNotifyTaskSnapshotChanged, msg);
                     break;
             }
         }
@@ -348,4 +357,14 @@
         forAllLocalListeners(mNotifyTaskProfileLocked, msg);
         msg.sendToTarget();
     }
+
+    /**
+     * Notify listeners that the snapshot of a task has changed.
+     */
+    void notifyTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) {
+        final Message msg = mHandler.obtainMessage(NOTIFY_TASK_SNAPSHOT_CHANGED_LISTENERS_MSG,
+                taskId, 0, snapshot);
+        forAllLocalListeners(mNotifyTaskSnapshotChanged, msg);
+        msg.sendToTarget();
+    }
 }
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 9e22c50..a72a958 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -52,6 +52,8 @@
 import com.android.internal.util.XmlUtils;
 
 import com.android.server.wm.TaskWindowContainerController;
+import com.android.server.wm.TaskWindowContainerListener;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -101,9 +103,11 @@
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityRecord.STARTING_WINDOW_SHOWN;
+import static com.android.server.am.ActivityStack.REMOVE_TASK_MODE_MOVING;
+import static com.android.server.am.ActivityStackSupervisor.CREATE_IF_NEEDED;
 import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
 
-final class TaskRecord extends ConfigurationContainer {
+final class TaskRecord extends ConfigurationContainer implements TaskWindowContainerListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "TaskRecord" : TAG_AM;
     private static final String TAG_ADD_REMOVE = TAG + POSTFIX_ADD_REMOVE;
     private static final String TAG_RECENTS = TAG + POSTFIX_RECENTS;
@@ -410,8 +414,8 @@
 
         final Rect bounds = updateOverrideConfigurationFromLaunchBounds();
         final Configuration overrideConfig = getOverrideConfiguration();
-        mWindowContainerController = new TaskWindowContainerController(taskId, getStackId(), userId,
-                bounds, overrideConfig, mResizeMode, isHomeTask(), isOnTopLauncher(), onTop,
+        mWindowContainerController = new TaskWindowContainerController(taskId, this, getStackId(),
+                userId, bounds, overrideConfig, mResizeMode, isHomeTask(), isOnTopLauncher(), onTop,
                 showForAllUsers);
     }
 
@@ -427,6 +431,11 @@
         mWindowContainerController = null;
     }
 
+    @Override
+    public void onSnapshotChanged(TaskSnapshot snapshot) {
+        mService.mTaskChangeNotificationController.notifyTaskSnapshotChanged(taskId, snapshot);
+    }
+
     void setResizeMode(int resizeMode) {
         if (mResizeMode == resizeMode) {
             return;
@@ -512,8 +521,8 @@
     }
 
     // TODO: Remove once we have a stack controller.
-    void positionWindowContainerAt(int stackId, int index) {
-        mWindowContainerController.positionAt(stackId, index, mBounds, getOverrideConfiguration());
+    void positionWindowContainerAt(int position) {
+        mWindowContainerController.positionAt(position, mBounds, getOverrideConfiguration());
     }
 
     // TODO: Replace with moveChildToTop?
@@ -534,9 +543,36 @@
         mWindowContainerController.getBounds(bounds);
     }
 
-    // TODO: make this part of adding it to the stack?
-    void reparentWindowContainer(int stackId, int position) {
-        mWindowContainerController.reparent(stackId, position);
+    // TODO: Should we be doing all the stuff in ASS.moveTaskToStackLocked?
+    void reparent(int stackId, int position, String reason) {
+        mService.mWindowManager.deferSurfaceLayout();
+
+        try {
+            final ActivityStackSupervisor supervisor = mService.mStackSupervisor;
+            final ActivityStack newStack = supervisor.getStack(stackId,
+                    CREATE_IF_NEEDED, false /* toTop */);
+            // Adjust the position for the new parent stack as needed.
+            position = newStack.getAdjustedPositionForTask(this, position, null /* starting */);
+
+            // Must reparent first in window manager to avoid a situation where AM can delete the
+            // we are coming from in WM before we reparent because it became empty.
+            mWindowContainerController.reparent(stackId, position);
+
+            final ActivityStack prevStack = mStack;
+            prevStack.removeTask(this, reason, REMOVE_TASK_MODE_MOVING);
+            newStack.addTask(this, position, reason);
+
+            supervisor.scheduleReportPictureInPictureModeChangedIfNeeded(this, prevStack);
+
+            if (voiceSession != null) {
+                try {
+                    voiceSession.taskStarted(intent, taskId);
+                } catch (RemoteException e) {
+                }
+            }
+        } finally {
+            mService.mWindowManager.continueSurfaceLayout();
+        }
     }
 
     void cancelWindowTransition() {
@@ -978,6 +1014,8 @@
         addActivityAtIndex(mActivities.size(), r);
     }
 
+    // TODO: Figure-out if any of the call points expect the window container to be reparented and
+    // correct them to use the right method.
     void addActivityAtIndex(int index, ActivityRecord r) {
         // Remove r first, and if it wasn't already in the list and it's fullscreen, count it.
         if (!mActivities.remove(r) && r.fullscreen) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 71ebad9..f516e99 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -259,6 +259,11 @@
                     int uptimeSeconds = (int)(SystemClock.elapsedRealtime() / 1000);
                     MetricsLogger.histogram(mInjector.getContext(),
                             "framework_locked_boot_completed", uptimeSeconds);
+                    final int MAX_UPTIME_SECONDS = 120;
+                    if (uptimeSeconds > MAX_UPTIME_SECONDS) {
+                        Slog.wtf("SystemServerTiming",
+                                "finishUserBoot took too long. uptimeSeconds=" + uptimeSeconds);
+                    }
                 }
 
                 mHandler.sendMessage(mHandler.obtainMessage(REPORT_LOCKED_BOOT_COMPLETE_MSG,
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0f3f9ce..df5f01d 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -144,7 +144,8 @@
  */
 public class AudioService extends IAudioService.Stub
         implements AccessibilityManager.TouchExplorationStateChangeListener,
-            AccessibilityManager.AccessibilityStateChangeListener{
+            AccessibilityManager.AccessibilityStateChangeListener,
+            AccessibilityManager.AccessibilityServicesStateChangeListener {
 
     private static final String TAG = "AudioService";
 
@@ -780,7 +781,7 @@
                 TAG,
                 SAFE_VOLUME_CONFIGURE_TIMEOUT_MS);
 
-        initA11yMonitoring(mContext);
+        initA11yMonitoring();
         onIndicateSystemReady();
     }
 
@@ -5925,13 +5926,25 @@
     //==========================================================================================
     // Accessibility
 
-    private void initA11yMonitoring(Context ctxt) {
-        AccessibilityManager accessibilityManager =
-                (AccessibilityManager) ctxt.getSystemService(Context.ACCESSIBILITY_SERVICE);
+    /**
+     * Compile-time constant to enable the use of an independent a11y volume:
+     * - set to true to listen to a11y services state changes and read
+     *   the whether any exposes the FLAG_ENABLE_ACCESSIBILITY_VOLUME flag
+     * - set to false to listen to when accessibility services are started (e.g. "TalkBack started")
+     */
+    private static final boolean USE_FLAG_ENABLE_ACCESSIBILITY_VOLUME = true;
+
+    private void initA11yMonitoring() {
+        final AccessibilityManager accessibilityManager =
+                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
         updateDefaultStreamOverrideDelay(accessibilityManager.isTouchExplorationEnabled());
         updateA11yVolumeAlias(accessibilityManager.isEnabled());
         accessibilityManager.addTouchExplorationStateChangeListener(this);
-        accessibilityManager.addAccessibilityStateChangeListener(this);
+        if (USE_FLAG_ENABLE_ACCESSIBILITY_VOLUME) {
+            accessibilityManager.addAccessibilityServicesStateChangeListener(this);
+        } else {
+            accessibilityManager.addAccessibilityStateChangeListener(this);
+        }
     }
 
     //---------------------------------------------------------------------------------
@@ -5969,21 +5982,31 @@
 
     private static boolean sIndependentA11yVolume = false;
 
+    // implementation of AccessibilityStateChangeListener
     @Override
     public void onAccessibilityStateChanged(boolean enabled) {
         updateA11yVolumeAlias(enabled);
     }
 
-    private void updateA11yVolumeAlias(boolean a11Enabled) {
-        if (DEBUG_VOL) Log.d(TAG, "Accessibility mode changed to " + a11Enabled);
-        // a11y has its own volume stream when a11y service is enabled
-        sIndependentA11yVolume = a11Enabled;
-        // update the volume mapping scheme
-        updateStreamVolumeAlias(true /*updateVolumes*/, TAG);
-        // update the volume controller behavior
-        mVolumeController.setA11yMode(sIndependentA11yVolume ?
-                VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
-                    VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
+    // implementation of AccessibilityServicesStateChangeListener
+    @Override
+    public void onAccessibilityServicesStateChanged() {
+        final AccessibilityManager accessibilityManager =
+                (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
+        updateA11yVolumeAlias(accessibilityManager.isAccessibilityVolumeStreamActive());
+    }
+
+    private void updateA11yVolumeAlias(boolean a11VolEnabled) {
+        if (DEBUG_VOL) Log.d(TAG, "Accessibility volume enabled = " + a11VolEnabled);
+        if (sIndependentA11yVolume != a11VolEnabled) {
+            sIndependentA11yVolume = a11VolEnabled;
+            // update the volume mapping scheme
+            updateStreamVolumeAlias(true /*updateVolumes*/, TAG);
+            // update the volume controller behavior
+            mVolumeController.setA11yMode(sIndependentA11yVolume ?
+                    VolumePolicy.A11Y_MODE_INDEPENDENT_A11Y_VOLUME :
+                        VolumePolicy.A11Y_MODE_MEDIA_A11Y_VOLUME);
+        }
     }
 
     //==========================================================================================
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 927dfd5..4c950de 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -16,6 +16,9 @@
 
 package com.android.server.connectivity.tethering;
 
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
@@ -142,7 +145,11 @@
         // message to aid in any subsequent debugging
         if (DBG) Log.d(TAG, "requesting mobile upstream network: " + mobileUpstreamRequest);
 
-        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback);
+        // The following use of the legacy type system cannot be removed until
+        // after upstream selection no longer finds networks by legacy type.
+        // See also b/34364553.
+        final int apnType = mDunRequired ? TYPE_MOBILE_DUN : TYPE_MOBILE_HIPRI;
+        cm().requestNetwork(mobileUpstreamRequest, mMobileNetworkCallback, 0, apnType);
     }
 
     public void releaseMobileNetworkRequest() {
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index d65e257..14f2e86 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -16,17 +16,16 @@
 
 package com.android.server.fingerprint;
 
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import android.content.Context;
 import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintDaemon;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.system.ErrnoException;
 import android.util.Slog;
 
 /**
@@ -85,7 +84,7 @@
                 try {
                     Slog.w(TAG, "Forcing lockout (fp driver code should do this!)");
                     receiver.onError(getHalDeviceId(),
-                            FingerprintManager.FINGERPRINT_ERROR_LOCKOUT);
+                            FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, 0 /* vendorCode */);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Failed to notify lockout:", e);
                 }
@@ -106,7 +105,7 @@
      */
     @Override
     public int start() {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "start authentication: no fingeprintd!");
             return ERROR_ESRCH;
@@ -116,7 +115,7 @@
             if (result != 0) {
                 Slog.w(TAG, "startAuthentication failed, result=" + result);
                 MetricsLogger.histogram(getContext(), "fingeprintd_auth_start_error", result);
-                onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+                onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
                 return result;
             }
             if (DEBUG) Slog.w(TAG, "client " + getOwnerString() + " is authenticating...");
@@ -129,13 +128,13 @@
 
     @Override
     public int stop(boolean initiatedByClient) {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "stopAuthentication: no fingeprintd!");
             return ERROR_ESRCH;
         }
         try {
-            final int result = daemon.cancelAuthentication();
+            final int result = daemon.cancel();
             if (result != 0) {
                 Slog.w(TAG, "stopAuthentication failed, result=" + result);
                 return result;
@@ -149,19 +148,19 @@
     }
 
     @Override
-    public boolean onEnrollResult(int fingerId, int groupId, int rem) {
+    public boolean onEnrollResult(int fingerId, int groupId, int remaining) {
         if (DEBUG) Slog.w(TAG, "onEnrollResult() called for authenticate!");
         return true; // Invalid for Authenticate
     }
 
     @Override
-    public boolean onRemoved(int fingerId, int groupId) {
+    public boolean onRemoved(int fingerId, int groupId, int remaining) {
         if (DEBUG) Slog.w(TAG, "onRemoved() called for authenticate!");
         return true; // Invalid for Authenticate
     }
 
     @Override
-    public boolean onEnumerationResult(int fingerId, int groupId) {
+    public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
         if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for authenticate!");
         return true; // Invalid for Authenticate
     }
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
index 8163b79..5a1e445 100644
--- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java
+++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
@@ -18,8 +18,8 @@
 
 import android.Manifest;
 import android.content.Context;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintDaemon;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -94,7 +94,7 @@
     /**
      * Gets the fingerprint daemon from the cached state in the container class.
      */
-    public abstract IFingerprintDaemon getFingerprintDaemon();
+    public abstract IBiometricsFingerprint getFingerprintDaemon();
 
     // Event callbacks from driver. Inappropriate calls is flagged/logged by the
     // respective client (e.g. enrolling shouldn't get authenticate events).
@@ -102,8 +102,8 @@
     // to the next client (e.g. authentication accepts or rejects a fingerprint).
     public abstract boolean onEnrollResult(int fingerId, int groupId, int rem);
     public abstract boolean onAuthenticated(int fingerId, int groupId);
-    public abstract boolean onRemoved(int fingerId, int groupId);
-    public abstract boolean onEnumerationResult(int fingerId, int groupId);
+    public abstract boolean onRemoved(int fingerId, int groupId, int remaining);
+    public abstract boolean onEnumerationResult(int fingerId, int groupId, int remaining);
 
     /**
      * Called when we get notification from fingerprintd that an image has been acquired.
@@ -111,11 +111,11 @@
      * @param acquiredInfo info about the current image acquisition
      * @return true if client should be removed
      */
-    public boolean onAcquired(int acquiredInfo) {
+    public boolean onAcquired(int acquiredInfo, int vendorCode) {
         if (mReceiver == null)
             return true; // client not connected
         try {
-            mReceiver.onAcquired(getHalDeviceId(), acquiredInfo);
+            mReceiver.onAcquired(getHalDeviceId(), acquiredInfo, vendorCode);
             return false; // acquisition continues...
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to invoke sendAcquired:", e);
@@ -134,10 +134,10 @@
      * @param error
      * @return true if client should be removed
      */
-    public boolean onError(int error) {
+    public boolean onError(int error, int vendorCode) {
         if (mReceiver != null) {
             try {
-                mReceiver.onError(getHalDeviceId(), error);
+                mReceiver.onError(getHalDeviceId(), error, vendorCode);
             } catch (RemoteException e) {
                 Slog.w(TAG, "Failed to invoke sendError:", e);
             }
@@ -162,7 +162,7 @@
     public void binderDied() {
         mToken = null;
         mReceiver = null;
-        onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+        onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
     }
 
     @Override
@@ -170,7 +170,7 @@
         try {
             if (mToken != null) {
                 if (DEBUG) Slog.w(TAG, "removing leaked reference: " + mToken);
-                onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+                onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
             }
         } finally {
             super.finalize();
diff --git a/services/core/java/com/android/server/fingerprint/EnrollClient.java b/services/core/java/com/android/server/fingerprint/EnrollClient.java
index c70ca7f..eddcd5b 100644
--- a/services/core/java/com/android/server/fingerprint/EnrollClient.java
+++ b/services/core/java/com/android/server/fingerprint/EnrollClient.java
@@ -17,8 +17,8 @@
 package com.android.server.fingerprint;
 
 import android.content.Context;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintDaemon;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -78,7 +78,7 @@
 
     @Override
     public int start() {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "enroll: no fingeprintd!");
             return ERROR_ESRCH;
@@ -89,7 +89,7 @@
             if (result != 0) {
                 Slog.w(TAG, "startEnroll failed, result=" + result);
                 MetricsLogger.histogram(getContext(), "fingerprintd_enroll_start_error", result);
-                onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+                onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
                 return result;
             }
         } catch (RemoteException e) {
@@ -100,13 +100,13 @@
 
     @Override
     public int stop(boolean initiatedByClient) {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "stopEnrollment: no fingeprintd!");
             return ERROR_ESRCH;
         }
         try {
-            final int result = daemon.cancelEnrollment();
+            final int result = daemon.cancel();
             if (result != 0) {
                 Slog.w(TAG, "startEnrollCancel failed, result = " + result);
                 return result;
@@ -115,19 +115,19 @@
             Slog.e(TAG, "stopEnrollment failed", e);
         }
         if (initiatedByClient) {
-            onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+            onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, 0 /* vendorCode */);
         }
         return 0;
     }
 
     @Override
-    public boolean onRemoved(int fingerId, int groupId) {
+    public boolean onRemoved(int fingerId, int groupId, int remaining) {
         if (DEBUG) Slog.w(TAG, "onRemoved() called for enroll!");
         return true; // Invalid for EnrollClient
     }
 
     @Override
-    public boolean onEnumerationResult(int fingerId, int groupId) {
+    public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
         if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for enroll!");
         return true; // Invalid for EnrollClient
     }
diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
index 26b1916..55bf689 100644
--- a/services/core/java/com/android/server/fingerprint/EnumerateClient.java
+++ b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
@@ -17,8 +17,8 @@
 package com.android.server.fingerprint;
 
 import android.content.Context;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintDaemon;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -30,14 +30,14 @@
  */
 public abstract class EnumerateClient extends ClientMonitor {
     public EnumerateClient(Context context, long halDeviceId, IBinder token,
-            IFingerprintServiceReceiver receiver, int userId, int groupId,
-            boolean restricted, String owner) {
+        IFingerprintServiceReceiver receiver, int groupId, int userId,
+        boolean restricted, String owner) {
         super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
     }
 
     @Override
     public int start() {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
         // The fingerprint template ids will be removed when we get confirmation from the HAL
         try {
             final int result = daemon.enumerate();
@@ -45,50 +45,69 @@
                 Slog.w(TAG, "start enumerate for user " + getTargetUserId()
                     + " failed, result=" + result);
                 MetricsLogger.histogram(getContext(), "fingerprintd_enum_start_error", result);
-                onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+                onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
                 return result;
             }
         } catch (RemoteException e) {
-            Slog.e(TAG, "startRemove failed", e);
+            Slog.e(TAG, "startEnumeration failed", e);
         }
         return 0;
     }
 
     @Override
     public int stop(boolean initiatedByClient) {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "stopAuthentication: no fingeprintd!");
             return ERROR_ESRCH;
         }
         try {
-            final int result = daemon.cancelEnumeration();
+            final int result = daemon.cancel();
             if (result != 0) {
                 Slog.w(TAG, "stop enumeration failed, result=" + result);
                 return result;
             }
         } catch (RemoteException e) {
-            Slog.e(TAG, "stop enumeration failed", e);
+            Slog.e(TAG, "stopEnumeration failed", e);
             return ERROR_ESRCH;
         }
+
         // We don't actually stop enumerate, but inform the client that the cancel operation
         // succeeded so we can start the next operation.
         if (initiatedByClient) {
-            onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+            onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, 0 /* vendorCode */);
         }
         return 0; // success
     }
 
     @Override
-    public boolean onEnumerationResult(int fingerId, int groupId) {
+    public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
         IFingerprintServiceReceiver receiver = getReceiver();
         if (receiver == null)
             return true; // client not listening
         try {
-            receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
+            receiver.onEnumerated(getHalDeviceId(), fingerId, groupId, remaining);
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to notify enumerated:", e);
         }
         return fingerId == 0; // done when id hits 0
     }
+
+    @Override
+    public boolean onAuthenticated(int fingerId, int groupId) {
+        if (DEBUG) Slog.w(TAG, "onAuthenticated() called for enumerate!");
+        return true; // Invalid for Enumerate.
+    }
+
+    @Override
+    public boolean onEnrollResult(int fingerId, int groupId, int rem) {
+        if (DEBUG) Slog.w(TAG, "onEnrollResult() called for enumerate!");
+        return true; // Invalid for Remove
+    }
+
+    @Override
+    public boolean onRemoved(int fingerId, int groupId, int remaining) {
+        if (DEBUG) Slog.w(TAG, "onRemoved() called for enumerate!");
+        return true; // Invalid for Authenticate
+    }
 }
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index b0f67a8..997222c 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -37,12 +37,12 @@
 import android.os.Environment;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.IHwBinder;
 import android.os.IRemoteCallback;
 import android.os.PowerManager;
 import android.os.PowerManager.WakeLock;
 import android.os.RemoteException;
 import android.os.SELinux;
-import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -61,11 +61,12 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprintClientCallback;
+
 import android.hardware.fingerprint.Fingerprint;
 import android.hardware.fingerprint.FingerprintManager;
 import android.hardware.fingerprint.IFingerprintService;
-import android.hardware.fingerprint.IFingerprintDaemon;
-import android.hardware.fingerprint.IFingerprintDaemonCallback;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
@@ -78,7 +79,6 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
@@ -90,11 +90,11 @@
  *
  * @hide
  */
-public class FingerprintService extends SystemService implements IBinder.DeathRecipient {
+public class FingerprintService extends SystemService implements IHwBinder.DeathRecipient {
     static final String TAG = "FingerprintService";
     static final boolean DEBUG = true;
     private static final String FP_DATA_DIR = "fpdata";
-    private static final String FINGERPRINTD = "android.hardware.fingerprint.IFingerprintDaemon";
+    private static final String FINGERPRINT_HIDL = "fingerprint_hal";
     private static final int MSG_USER_SWITCHING = 10;
     private static final String ACTION_LOCKOUT_RESET =
             "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";
@@ -120,7 +120,7 @@
     private long mHalDeviceId;
     private int mFailedAttempts;
     @GuardedBy("this")
-    private IFingerprintDaemon mDaemon;
+    private IBiometricsFingerprint mDaemon;
     private final PowerManager mPowerManager;
     private final AlarmManager mAlarmManager;
     private final UserManager mUserManager;
@@ -130,12 +130,10 @@
     private PerformanceStats mPerformanceStats;
 
     // Normal fingerprint authentications are tracked by mPerformanceMap.
-    private HashMap<Integer, PerformanceStats> mPerformanceMap
-            = new HashMap<Integer, PerformanceStats>();
+    private HashMap<Integer, PerformanceStats> mPerformanceMap = new HashMap<>();
 
     // Transactions that make use of CryptoObjects are tracked by mCryptoPerformaceMap.
-    private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap
-            = new HashMap<Integer, PerformanceStats>();
+    private HashMap<Integer, PerformanceStats> mCryptoPerformanceMap = new HashMap<>();
 
     private Handler mHandler = new Handler() {
         @Override
@@ -201,59 +199,61 @@
     }
 
     @Override
-    public void binderDied() {
+    public void serviceDied(long cookie) {
         Slog.v(TAG, "fingerprintd died");
         MetricsLogger.count(mContext, "fingerprintd_died", 1);
         synchronized (this) {
             mDaemon = null;
         }
         mCurrentUserId = UserHandle.USER_CURRENT;
-        handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+        handleError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE,
+                0 /*vendorCode */);
     }
 
-    public IFingerprintDaemon getFingerprintDaemon() {
-        synchronized (this) {
-            if (mDaemon == null) {
-                mDaemon = IFingerprintDaemon.Stub
-                        .asInterface(ServiceManager.getService(FINGERPRINTD));
-                if (mDaemon != null) {
-                    try {
-                        mDaemon.asBinder().linkToDeath(this, 0);
-                        mDaemon.init(mDaemonCallback);
-                        mHalDeviceId = mDaemon.openHal();
-                        if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
-                        if (mHalDeviceId != 0) {
-                            updateActiveGroup(ActivityManager.getCurrentUser(), null);
-                        } else {
-                            Slog.w(TAG, "Failed to open Fingerprint HAL!");
-                            MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
-                            mDaemon = null;
-                        }
-                    } catch (RemoteException e) {
-                        Slog.e(TAG, "Failed to open fingeprintd HAL", e);
-                        mDaemon = null; // try again later!
-                    }
-                } else {
-                    Slog.w(TAG, "fingerprint service not available");
-                }
+    public synchronized IBiometricsFingerprint getFingerprintDaemon() {
+        if (mDaemon == null) {
+            try {
+                mDaemon = IBiometricsFingerprint.getService(FINGERPRINT_HIDL);
+            } catch (java.util.NoSuchElementException e) {
+                // Service doesn't exist or cannot be opened. Logged below.
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to get biometric interface", e);
             }
-            return mDaemon;
+            if (mDaemon == null) {
+                Slog.w(TAG, "fingerprint HIDL not available");
+                return null;
+            }
+
+            mDaemon.asBinder().linkToDeath(this, 0);
+
+            try {
+                mHalDeviceId = mDaemon.setNotify(mDaemonCallback);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Failed to open fingeprintd HAL", e);
+                mDaemon = null; // try again later!
+            }
+
+            if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
+            if (mHalDeviceId != 0) {
+                updateActiveGroup(ActivityManager.getCurrentUser(), null);
+            } else {
+                Slog.w(TAG, "Failed to open Fingerprint HAL!");
+                MetricsLogger.count(mContext, "fingerprintd_openhal_error", 1);
+                mDaemon = null;
+            }
         }
+        return mDaemon;
     }
 
-    protected void handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
-        if (fingerIds.length != groupIds.length) {
-            Slog.w(TAG, "fingerIds and groupIds differ in length: f[]="
-                    + Arrays.toString(fingerIds) + ", g[]=" + Arrays.toString(groupIds));
-            return;
-        }
-        if (DEBUG) Slog.w(TAG, "Enumerate: f[]=" + fingerIds + ", g[]=" + groupIds);
-        // TODO: update fingerprint/name pairs
+    protected void handleEnumerate(long deviceId, int fingerId, int groupId, int remaining) {
+        if (DEBUG) Slog.w(TAG, "Enumerate: fid=" + fingerId + ", gid="
+                + groupId + "rem=" + remaining);
+        // TODO: coordinate names with framework
     }
 
-    protected void handleError(long deviceId, int error) {
+    protected void handleError(long deviceId, int error, int vendorCode) {
         ClientMonitor client = mCurrentClient;
-        if (client != null && client.onError(error)) {
+        if (client != null && client.onError(error, vendorCode)) {
             removeClient(client);
         }
         if (DEBUG) Slog.v(TAG, "handleError(client="
@@ -269,9 +269,9 @@
         }
     }
 
-    protected void handleRemoved(long deviceId, int fingerId, int groupId) {
+    protected void handleRemoved(long deviceId, int fingerId, int groupId, int remaining) {
         ClientMonitor client = mCurrentClient;
-        if (client != null && client.onRemoved(fingerId, groupId)) {
+        if (client != null && client.onRemoved(fingerId, groupId, remaining)) {
             removeClient(client);
         }
     }
@@ -288,9 +288,9 @@
         }
     }
 
-    protected void handleAcquired(long deviceId, int acquiredInfo) {
+    protected void handleAcquired(long deviceId, int acquiredInfo, int vendorCode) {
         ClientMonitor client = mCurrentClient;
-        if (client != null && client.onAcquired(acquiredInfo)) {
+        if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
             removeClient(client);
         }
         if (mPerformanceStats != null && !inLockoutMode()
@@ -349,7 +349,7 @@
     }
 
     public long startPreEnroll(IBinder token) {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "startPreEnroll: no fingeprintd!");
             return 0;
@@ -363,7 +363,7 @@
     }
 
     public int startPostEnroll(IBinder token) {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "startPostEnroll: no fingeprintd!");
             return 0;
@@ -403,7 +403,7 @@
 
     void startRemove(IBinder token, int fingerId, int groupId, int userId,
             IFingerprintServiceReceiver receiver, boolean restricted) {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
         if (daemon == null) {
             Slog.w(TAG, "startRemove: no fingeprintd!");
             return;
@@ -416,7 +416,29 @@
             }
 
             @Override
-            public IFingerprintDaemon getFingerprintDaemon() {
+            public IBiometricsFingerprint getFingerprintDaemon() {
+                return FingerprintService.this.getFingerprintDaemon();
+            }
+        };
+        startClient(client, true);
+    }
+
+    void startEnumerate(IBinder token, int userId,
+        IFingerprintServiceReceiver receiver, boolean restricted) {
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
+        if (daemon == null) {
+            Slog.w(TAG, "startEnumerate: no fingeprintd!");
+            return;
+        }
+        EnumerateClient client = new EnumerateClient(getContext(), mHalDeviceId, token,
+            receiver, userId, userId, restricted, token.toString()) {
+            @Override
+            public void notifyUserActivity() {
+                FingerprintService.this.userActivity();
+            }
+
+            @Override
+            public IBiometricsFingerprint getFingerprintDaemon() {
                 return FingerprintService.this.getFingerprintDaemon();
             }
         };
@@ -580,7 +602,7 @@
             }
 
             @Override
-            public IFingerprintDaemon getFingerprintDaemon() {
+            public IBiometricsFingerprint getFingerprintDaemon() {
                 return FingerprintService.this.getFingerprintDaemon();
             }
         };
@@ -588,7 +610,7 @@
         if (inLockoutMode()) {
             Slog.v(TAG, "In lockout mode; disallowing authentication");
             // Don't bother starting the client. Just send the error message.
-            if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT)) {
+            if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, 0 /* vendorCode */)) {
                 Slog.w(TAG, "Cannot send timeout message to client");
             }
             return;
@@ -607,7 +629,7 @@
                 userId, groupId, cryptoToken, restricted, opPackageName) {
 
             @Override
-            public IFingerprintDaemon getFingerprintDaemon() {
+            public IBiometricsFingerprint getFingerprintDaemon() {
                 return FingerprintService.this.getFingerprintDaemon();
             }
 
@@ -674,7 +696,8 @@
         };
     }
 
-    private IFingerprintDaemonCallback mDaemonCallback = new IFingerprintDaemonCallback.Stub() {
+    private IBiometricsFingerprintClientCallback mDaemonCallback =
+            new IBiometricsFingerprintClientCallback.Stub() {
 
         @Override
         public void onEnrollResult(final long deviceId, final int fingerId, final int groupId,
@@ -688,11 +711,11 @@
         }
 
         @Override
-        public void onAcquired(final long deviceId, final int acquiredInfo) {
+        public void onAcquired(final long deviceId, final int acquiredInfo, final int vendorCode) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    handleAcquired(deviceId, acquiredInfo);
+                    handleAcquired(deviceId, acquiredInfo, vendorCode);
                 }
             });
         }
@@ -708,31 +731,32 @@
         }
 
         @Override
-        public void onError(final long deviceId, final int error) {
+        public void onError(final long deviceId, final int error, final int vendorCode) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    handleError(deviceId, error);
+                    handleError(deviceId, error, vendorCode);
                 }
             });
         }
 
         @Override
-        public void onRemoved(final long deviceId, final int fingerId, final int groupId) {
+        public void onRemoved(final long deviceId, final int fingerId, final int groupId, final int remaining) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    handleRemoved(deviceId, fingerId, groupId);
+                    handleRemoved(deviceId, fingerId, groupId, remaining);
                 }
             });
         }
 
         @Override
-        public void onEnumerate(final long deviceId, final int[] fingerIds, final int[] groupIds) {
+        public void onEnumerate(final long deviceId, final int fingerId, final int groupId,
+                final int remaining) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    handleEnumerate(deviceId, fingerIds, groupIds);
+                    handleEnumerate(deviceId, fingerId, groupId, remaining);
                 }
             });
         }
@@ -889,6 +913,19 @@
 
         }
 
+        public void enumerate(final IBinder token, final int userId,
+            final IFingerprintServiceReceiver receiver) {
+            checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
+            final boolean restricted = isRestricted();
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    startEnumerate(token, userId, receiver, restricted);
+                }
+            });
+
+        }
+
         @Override // Binder call
         public boolean isHardwareDetected(long deviceId, String opPackageName) {
             if (!canUseFingerprint(opPackageName, false /* foregroundOnly */,
@@ -1082,7 +1119,7 @@
     }
 
     private void updateActiveGroup(int userId, String clientPackage) {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
 
         if (daemon != null) {
             try {
@@ -1103,7 +1140,7 @@
                             return;
                         }
                     }
-                    daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
+                    daemon.setActiveGroup(userId, fpDir.getAbsolutePath());
                     mCurrentUserId = userId;
                 }
                 mCurrentAuthenticatorId = daemon.getAuthenticatorId();
@@ -1155,5 +1192,4 @@
     public long getAuthenticatorId(String opPackageName) {
         return mCurrentAuthenticatorId;
     }
-
 }
diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
index f939f41..ab1b9728 100644
--- a/services/core/java/com/android/server/fingerprint/RemovalClient.java
+++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java
@@ -17,8 +17,8 @@
 package com.android.server.fingerprint;
 
 import android.content.Context;
+import android.hardware.biometrics.fingerprint.V2_1.IBiometricsFingerprint;
 import android.hardware.fingerprint.FingerprintManager;
-import android.hardware.fingerprint.IFingerprintDaemon;
 import android.hardware.fingerprint.IFingerprintServiceReceiver;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -41,14 +41,14 @@
 
     @Override
     public int start() {
-        IFingerprintDaemon daemon = getFingerprintDaemon();
+        IBiometricsFingerprint daemon = getFingerprintDaemon();
         // The fingerprint template ids will be removed when we get confirmation from the HAL
         try {
-            final int result = daemon.remove(mFingerId, getGroupId());
+            final int result = daemon.remove(getGroupId(), mFingerId);
             if (result != 0) {
                 Slog.w(TAG, "startRemove with id = " + mFingerId + " failed, result=" + result);
                 MetricsLogger.histogram(getContext(), "fingerprintd_remove_start_error", result);
-                onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
+                onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
                 return result;
             }
         } catch (RemoteException e) {
@@ -62,7 +62,7 @@
         // We don't actually stop remove, but inform the client that the cancel operation succeeded
         // so we can start the next operation.
         if (initiatedByClient) {
-            onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED);
+            onError(FingerprintManager.FINGERPRINT_ERROR_CANCELED, 0 /* vendorCode */);
         }
         return 0;
     }
@@ -70,11 +70,12 @@
     /*
      * @return true if we're done.
      */
-    private boolean sendRemoved(int fingerId, int groupId) {
+    private boolean sendRemoved(int fingerId, int groupId, int remaining) {
         IFingerprintServiceReceiver receiver = getReceiver();
         try {
             if (receiver != null) {
-                receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
+                // TODO: plumb remaining
+                receiver.onRemoved(getHalDeviceId(), fingerId, groupId, remaining);
             }
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to notify Removed:", e);
@@ -83,12 +84,12 @@
     }
 
     @Override
-    public boolean onRemoved(int fingerId, int groupId) {
+    public boolean onRemoved(int fingerId, int groupId, int remaining) {
         if (fingerId != 0) {
             FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(), fingerId,
                     getTargetUserId());
         }
-        return sendRemoved(fingerId, getGroupId());
+        return sendRemoved(fingerId, getGroupId(), remaining);
     }
 
     @Override
@@ -104,9 +105,9 @@
     }
 
     @Override
-    public boolean onEnumerationResult(int fingerId, int groupId) {
+    public boolean onEnumerationResult(int fingerId, int groupId, int remaining) {
         if (DEBUG) Slog.w(TAG, "onEnumerationResult() called for remove!");
-        return false; // Invalid for Remove.
+        return true; // Invalid for Remove.
     }
 
 
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 87f4030..fbb39384 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -25,6 +25,7 @@
 import com.android.internal.inputmethod.InputMethodSubtypeHandle;
 import com.android.internal.os.SomeArgs;
 import com.android.internal.R;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.server.DisplayThread;
 import com.android.server.LocalServices;
@@ -1700,6 +1701,7 @@
     // Binder call
     @Override
     public void setCustomPointerIcon(PointerIcon icon) {
+        Preconditions.checkNotNull(icon);
         nativeSetCustomPointerIcon(mPtr, icon);
     }
 
diff --git a/services/core/java/com/android/server/net/NetworkIdentitySet.java b/services/core/java/com/android/server/net/NetworkIdentitySet.java
index c48f430..ee00fdc 100644
--- a/services/core/java/com/android/server/net/NetworkIdentitySet.java
+++ b/services/core/java/com/android/server/net/NetworkIdentitySet.java
@@ -17,6 +17,8 @@
 package com.android.server.net;
 
 import android.net.NetworkIdentity;
+import android.service.NetworkIdentitySetProto;
+import android.util.proto.ProtoOutputStream;
 
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
@@ -143,4 +145,14 @@
         final NetworkIdentity anotherIdent = another.iterator().next();
         return ident.compareTo(anotherIdent);
     }
+
+    public void writeToProto(ProtoOutputStream proto, long tag) {
+        final long start = proto.start(tag);
+
+        for (NetworkIdentity ident : this) {
+            ident.writeToProto(proto, NetworkIdentitySetProto.IDENTITIES);
+        }
+
+        proto.end(start);
+    }
 }
diff --git a/services/core/java/com/android/server/net/NetworkStatsCollection.java b/services/core/java/com/android/server/net/NetworkStatsCollection.java
index c45b416..0354300 100644
--- a/services/core/java/com/android/server/net/NetworkStatsCollection.java
+++ b/services/core/java/com/android/server/net/NetworkStatsCollection.java
@@ -34,9 +34,13 @@
 import android.net.NetworkTemplate;
 import android.net.TrafficStats;
 import android.os.Binder;
+import android.service.NetworkStatsCollectionKeyProto;
+import android.service.NetworkStatsCollectionProto;
+import android.service.NetworkStatsCollectionStatsProto;
 import android.util.ArrayMap;
 import android.util.AtomicFile;
 import android.util.IntArray;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FileRotator;
@@ -532,12 +536,15 @@
                 / mBucketDuration);
     }
 
-    public void dump(IndentingPrintWriter pw) {
+    private ArrayList<Key> getSortedKeys() {
         final ArrayList<Key> keys = Lists.newArrayList();
         keys.addAll(mStats.keySet());
         Collections.sort(keys);
+        return keys;
+    }
 
-        for (Key key : keys) {
+    public void dump(IndentingPrintWriter pw) {
+        for (Key key : getSortedKeys()) {
             pw.print("ident="); pw.print(key.ident.toString());
             pw.print(" uid="); pw.print(key.uid);
             pw.print(" set="); pw.print(NetworkStats.setToString(key.set));
@@ -550,6 +557,29 @@
         }
     }
 
+    public void writeToProto(ProtoOutputStream proto, long tag) {
+        final long start = proto.start(tag);
+
+        for (Key key : getSortedKeys()) {
+            final long startStats = proto.start(NetworkStatsCollectionProto.STATS);
+
+            // Key
+            final long startKey = proto.start(NetworkStatsCollectionStatsProto.KEY);
+            key.ident.writeToProto(proto, NetworkStatsCollectionKeyProto.IDENTITY);
+            proto.write(NetworkStatsCollectionKeyProto.UID, key.uid);
+            proto.write(NetworkStatsCollectionKeyProto.SET, key.set);
+            proto.write(NetworkStatsCollectionKeyProto.TAG, key.tag);
+            proto.end(startKey);
+
+            // Value
+            final NetworkStatsHistory history = mStats.get(key);
+            history.writeToProto(proto, NetworkStatsCollectionStatsProto.HISTORY);
+            proto.end(startStats);
+        }
+
+        proto.end(start);
+    }
+
     public void dumpCheckin(PrintWriter pw, long start, long end) {
         dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateMobileWildcard(), "cell");
         dumpCheckin(pw, start, end, NetworkTemplate.buildTemplateWifiWildcard(), "wifi");
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 090a076..80309e1 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -29,9 +29,11 @@
 import android.net.NetworkTemplate;
 import android.net.TrafficStats;
 import android.os.DropBoxManager;
+import android.service.NetworkStatsRecorderProto;
 import android.util.Log;
 import android.util.MathUtils;
 import android.util.Slog;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.net.VpnInfo;
 import com.android.internal.util.FileRotator;
@@ -465,6 +467,15 @@
         }
     }
 
+    public void writeToProtoLocked(ProtoOutputStream proto, long tag) {
+        final long start = proto.start(tag);
+        if (mPending != null) {
+            proto.write(NetworkStatsRecorderProto.PENDING_TOTAL_BYTES, mPending.getTotalBytes());
+        }
+        getOrLoadCompleteLocked().writeToProto(proto, NetworkStatsRecorderProto.COMPLETE_HISTORY);
+        proto.end(start);
+    }
+
     public void dumpCheckin(PrintWriter pw, long start, long end) {
         // Only load and dump stats from the requested window
         getOrLoadPartialLocked(start, end).dumpCheckin(pw, start, end);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 386e78b..104c296 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -104,6 +104,8 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
+import android.service.NetworkInterfaceProto;
+import android.service.NetworkStatsServiceDumpProto;
 import android.telephony.TelephonyManager;
 import android.text.format.DateUtils;
 import android.util.ArrayMap;
@@ -115,6 +117,7 @@
 import android.util.Slog;
 import android.util.SparseIntArray;
 import android.util.TrustedTime;
+import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.net.VpnInfo;
@@ -1255,6 +1258,12 @@
         final IndentingPrintWriter pw = new IndentingPrintWriter(rawWriter, "  ");
 
         synchronized (mStatsLock) {
+            if (args.length > 0 && "--proto".equals(args[0])) {
+                // In this case ignore all other arguments.
+                dumpProto(fd);
+                return;
+            }
+
             if (poll) {
                 performPollLocked(FLAG_PERSIST_ALL | FLAG_PERSIST_FORCE);
                 pw.println("Forced poll");
@@ -1327,6 +1336,33 @@
         }
     }
 
+    private void dumpProto(FileDescriptor fd) {
+        final ProtoOutputStream proto = new ProtoOutputStream(fd);
+
+        // TODO Right now it writes all history.  Should it limit to the "since-boot" log?
+
+        dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_INTERFACES, mActiveIfaces);
+        dumpInterfaces(proto, NetworkStatsServiceDumpProto.ACTIVE_UID_INTERFACES, mActiveUidIfaces);
+        mDevRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.DEV_STATS);
+        mXtRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.XT_STATS);
+        mUidRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_STATS);
+        mUidTagRecorder.writeToProtoLocked(proto, NetworkStatsServiceDumpProto.UID_TAG_STATS);
+
+        proto.flush();
+    }
+
+    private static void dumpInterfaces(ProtoOutputStream proto, long tag,
+            ArrayMap<String, NetworkIdentitySet> ifaces) {
+        for (int i = 0; i < ifaces.size(); i++) {
+            final long start = proto.start(tag);
+
+            proto.write(NetworkInterfaceProto.INTERFACE, ifaces.keyAt(i));
+            ifaces.valueAt(i).writeToProto(proto, NetworkInterfaceProto.IDENTITIES);
+
+            proto.end(start);
+        }
+    }
+
     /**
      * Return snapshot of current UID statistics, including any
      * {@link TrafficStats#UID_TETHERING} and {@link #mUidOperations} values.
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0cac406..9018302 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -3289,7 +3289,9 @@
     private boolean playSound(final NotificationRecord record, Uri soundUri) {
         boolean looping = (record.getNotification().flags & Notification.FLAG_INSISTENT) != 0;
         // do not play notifications if there is a user of exclusive audio focus
-        if (!mAudioManager.isAudioFocusExclusive()) {
+        // or the device is in vibrate mode
+        if (!mAudioManager.isAudioFocusExclusive() && mAudioManager.getRingerModeInternal()
+                != AudioManager.RINGER_MODE_VIBRATE) {
             final long identity = Binder.clearCallingIdentity();
             try {
                 final IRingtonePlayer player = mAudioManager.getRingtonePlayer();
@@ -3995,7 +3997,8 @@
             NotificationRecord childR = mNotificationList.get(i);
             StatusBarNotification childSbn = childR.sbn;
             if ((childSbn.isGroup() && !childSbn.getNotification().isGroupSummary()) &&
-                    childR.getGroupKey().equals(r.getGroupKey())) {
+                    childR.getGroupKey().equals(r.getGroupKey())
+                    && (childR.getFlags() & Notification.FLAG_FOREGROUND_SERVICE) == 0) {
                 EventLogTags.writeNotificationCancel(callingUid, callingPid, pkg, childSbn.getId(),
                         childSbn.getTag(), userId, 0, 0, reason, listenerName);
                 mNotificationList.remove(i);
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index 98249dd1..de0d2a3 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -415,6 +415,15 @@
         }
     }
 
+    public void invalidateMounts() throws InstallerException {
+        if (!checkBeforeRemote()) return;
+        try {
+            mInstalld.invalidateMounts();
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     private static void assertValidInstructionSet(String instructionSet)
             throws InstallerException {
         for (String abi : Build.SUPPORTED_ABIS) {
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 48e000d8..2ddf6db 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -21,9 +21,11 @@
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
 import android.app.AppGlobals;
+import android.app.PendingIntent;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ILauncherApps;
@@ -277,24 +279,11 @@
         @Override
         public ParceledListSlice<ResolveInfo> getLauncherActivities(String packageName, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user);
-            if (!isUserEnabled(user)) {
-                return null;
-            }
-
-            final Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
-            mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
-            mainIntent.setPackage(packageName);
-            long ident = Binder.clearCallingIdentity();
-            try {
-                List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(mainIntent,
-                        PackageManager.MATCH_DIRECT_BOOT_AWARE
-                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                        user.getIdentifier());
-                return new ParceledListSlice<>(apps);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+            return queryActivitiesForUser(
+                    new Intent(Intent.ACTION_MAIN)
+                            .addCategory(Intent.CATEGORY_LAUNCHER)
+                            .setPackage(packageName),
+                    user);
         }
 
         @Override
@@ -318,6 +307,53 @@
         }
 
         @Override
+        public ParceledListSlice getShortcutConfigActivities(String packageName, UserHandle user)
+                throws RemoteException {
+            return queryActivitiesForUser(
+                    new Intent(Intent.ACTION_CREATE_SHORTCUT).setPackage(packageName), user);
+        }
+
+        private ParceledListSlice<ResolveInfo> queryActivitiesForUser(Intent intent,
+                UserHandle user) {
+            ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user);
+            if (!isUserEnabled(user)) {
+                return null;
+            }
+
+            long ident = injectClearCallingIdentity();
+            try {
+                List<ResolveInfo> apps = mPm.queryIntentActivitiesAsUser(intent,
+                        PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                        user.getIdentifier());
+                return new ParceledListSlice<>(apps);
+            } finally {
+                injectRestoreCallingIdentity(ident);
+            }
+        }
+
+        @Override
+        public IntentSender getShortcutConfigActivityIntent(String callingPackage,
+                ComponentName component, UserHandle user) throws RemoteException {
+            ensureShortcutPermission(callingPackage, user);
+            Preconditions.checkNotNull(component);
+            Preconditions.checkArgument(isUserEnabled(user), "User not enabled");
+
+            // All right, create the sender.
+            Intent intent = new Intent(Intent.ACTION_CREATE_SHORTCUT).setComponent(component);
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                return PendingIntent.getActivityAsUser(
+                        mContext, 0, intent, PendingIntent.FLAG_ONE_SHOT
+                                | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT,
+                        null, user)
+                        .getIntentSender();
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        @Override
         public boolean isPackageEnabled(String packageName, UserHandle user)
                 throws RemoteException {
             ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user);
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index d25abbf..d516acf 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -145,6 +145,7 @@
     private static final String ATTR_ABI_OVERRIDE = "abiOverride";
     private static final String ATTR_VOLUME_UUID = "volumeUuid";
     private static final String ATTR_NAME = "name";
+    private static final String ATTR_INSTALL_REASON = "installRason";
 
     /** Automatically destroy sessions older than this */
     private static final long MAX_AGE_MILLIS = 3 * DateUtils.DAY_IN_MILLIS;
@@ -412,6 +413,7 @@
         params.abiOverride = readStringAttribute(in, ATTR_ABI_OVERRIDE);
         params.volumeUuid = readStringAttribute(in, ATTR_VOLUME_UUID);
         params.grantedRuntimePermissions = readGrantedRuntimePermissions(in);
+        params.installReason = readIntAttribute(in, ATTR_INSTALL_REASON);
 
         final File appIconFile = buildAppIconFile(sessionId);
         if (appIconFile.exists()) {
@@ -484,6 +486,7 @@
         writeUriAttribute(out, ATTR_REFERRER_URI, params.referrerUri);
         writeStringAttribute(out, ATTR_ABI_OVERRIDE, params.abiOverride);
         writeStringAttribute(out, ATTR_VOLUME_UUID, params.volumeUuid);
+        writeIntAttribute(out, ATTR_INSTALL_REASON, params.installReason);
 
         // Persist app icon if changed since last written
         final File appIconFile = buildAppIconFile(session.sessionId);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7362a51..af1e007 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1713,9 +1713,11 @@
             }
 
             // Now that we successfully installed the package, grant runtime
-            // permissions if requested before broadcasting the install.
-            if (grantPermissions && res.pkg.applicationInfo.targetSdkVersion
-                    >= Build.VERSION_CODES.M) {
+            // permissions if requested before broadcasting the install. Also
+            // for legacy apps in permission review mode we clear the permission
+            // review flag which is used to emulate runtime permissions for
+            // legacy apps.
+            if (grantPermissions) {
                 grantRequestedRuntimePermissions(res.pkg, res.newUsers, grantedPermissions);
             }
 
@@ -1958,11 +1960,6 @@
         for (int userId : userIds) {
             grantRequestedRuntimePermissionsForUser(pkg, userId, grantedPermissions);
         }
-
-        // We could have touched GID membership, so flush out packages.list
-        synchronized (mPackages) {
-            mSettings.writePackageListLPr();
-        }
     }
 
     private void grantRequestedRuntimePermissionsForUser(PackageParser.Package pkg, int userId,
@@ -1977,6 +1974,9 @@
         final int immutableFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
                 | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
 
+        final boolean supportsRuntimePermissions = pkg.applicationInfo.targetSdkVersion
+                >= Build.VERSION_CODES.M;
+
         for (String permission : pkg.requestedPermissions) {
             final BasePermission bp;
             synchronized (mPackages) {
@@ -1986,9 +1986,18 @@
                     && (grantedPermissions == null
                            || ArrayUtils.contains(grantedPermissions, permission))) {
                 final int flags = permissionsState.getPermissionFlags(permission, userId);
-                // Installer cannot change immutable permissions.
-                if ((flags & immutableFlags) == 0) {
-                    grantRuntimePermission(pkg.packageName, permission, userId);
+                if (supportsRuntimePermissions) {
+                    // Installer cannot change immutable permissions.
+                    if ((flags & immutableFlags) == 0) {
+                        grantRuntimePermission(pkg.packageName, permission, userId);
+                    }
+                } else if (mPermissionReviewRequired) {
+                    // In permission review mode we clear the review flag when we
+                    // are asked to install the app with all permissions granted.
+                    if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
+                        updatePermissionFlags(permission, pkg.packageName,
+                                PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0, userId);
+                    }
                 }
             }
         }
@@ -12208,6 +12217,67 @@
         mHandler.sendMessage(msg);
     }
 
+
+    /**
+     * Ensure that the install reason matches what we know about the package installer (e.g. whether
+     * it is acting on behalf on an enterprise or the user).
+     *
+     * Note that the ordering of the conditionals in this method is important. The checks we perform
+     * are as follows, in this order:
+     *
+     * 1) If the install is being performed by a system app, we can trust the app to have set the
+     *    install reason correctly. Thus, we pass through the install reason unchanged, no matter
+     *    what it is.
+     * 2) If the install is being performed by a device or profile owner app, the install reason
+     *    should be enterprise policy. However, we cannot be sure that the device or profile owner
+     *    set the install reason correctly. If the app targets an older SDK version where install
+     *    reasons did not exist yet, or if the app author simply forgot, the install reason may be
+     *    unset or wrong. Thus, we force the install reason to be enterprise policy.
+     * 3) In all other cases, the install is being performed by a regular app that is neither part
+     *    of the system nor a device or profile owner. We have no reason to believe that this app is
+     *    acting on behalf of the enterprise admin. Thus, we check whether the install reason was
+     *    set to enterprise policy and if so, change it to unknown instead.
+     */
+    private int fixUpInstallReason(String installerPackageName, int installerUid,
+            int installReason) {
+        if (checkUidPermission(android.Manifest.permission.INSTALL_PACKAGES, installerUid)
+                == PERMISSION_GRANTED) {
+            // If the install is being performed by a system app, we trust that app to have set the
+            // install reason correctly.
+            return installReason;
+        }
+
+        final IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface(
+            ServiceManager.getService(Context.DEVICE_POLICY_SERVICE));
+        if (dpm != null) {
+            ComponentName owner = null;
+            try {
+                owner = dpm.getDeviceOwnerComponent(true /* callingUserOnly */);
+                if (owner == null) {
+                    owner = dpm.getProfileOwner(UserHandle.getUserId(installerUid));
+                }
+            } catch (RemoteException e) {
+            }
+            if (owner != null && owner.getPackageName().equals(installerPackageName)) {
+                // If the install is being performed by a device or profile owner, the install
+                // reason should be enterprise policy.
+                return PackageManager.INSTALL_REASON_POLICY;
+            }
+        }
+
+        if (installReason == PackageManager.INSTALL_REASON_POLICY) {
+            // If the install is being performed by a regular app (i.e. neither system app nor
+            // device or profile owner), we have no reason to believe that the app is acting on
+            // behalf of an enterprise. If the app set the install reason to enterprise policy,
+            // change it to unknown instead.
+            return PackageManager.INSTALL_REASON_UNKNOWN;
+        }
+
+        // If the install is being performed by a regular app and the install reason was set to any
+        // value but enterprise policy, leave the install reason unchanged.
+        return installReason;
+    }
+
     void installStage(String packageName, File stagedDir, String stagedCid,
             IPackageInstallObserver2 observer, PackageInstaller.SessionParams sessionParams,
             String installerPackageName, int installerUid, UserHandle user,
@@ -12229,10 +12299,12 @@
         }
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
+        final int installReason = fixUpInstallReason(installerPackageName, installerUid,
+                sessionParams.installReason);
         final InstallParams params = new InstallParams(origin, null, observer,
                 sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
                 verificationInfo, user, sessionParams.abiOverride,
-                sessionParams.grantedRuntimePermissions, certificates, sessionParams.installReason);
+                sessionParams.grantedRuntimePermissions, certificates, installReason);
         params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
diff --git a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
index c8ddf0a..a156356 100644
--- a/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
+++ b/services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java
@@ -15,6 +15,7 @@
  */
 package com.android.server.pm;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
@@ -24,6 +25,7 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.LauncherApps.PinItemRequest;
 import android.content.pm.ShortcutInfo;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.util.Log;
@@ -50,18 +52,31 @@
     private static class PinItemRequestInner extends IPinItemRequest.Stub {
         protected final ShortcutRequestPinProcessor mProcessor;
         private final IntentSender mResultIntent;
+        private final int mLauncherUid;
 
         @GuardedBy("this")
         private boolean mAccepted;
 
         private PinItemRequestInner(ShortcutRequestPinProcessor processor,
-                IntentSender resultIntent) {
+                IntentSender resultIntent, int launcherUid) {
             mProcessor = processor;
             mResultIntent = resultIntent;
+            mLauncherUid = launcherUid;
+        }
+
+        /**
+         * Returns true if the caller is same as the default launcher app when this request
+         * object was created.
+         */
+        private boolean isCallerValid() {
+            return mProcessor.isCallerUid(mLauncherUid);
         }
 
         @Override
         public boolean isValid() {
+            if (!isCallerValid()) {
+                return false;
+            }
             // TODO When an app calls requestPinShortcut(), all pending requests should be
             // invalidated.
             synchronized (this) {
@@ -76,6 +91,9 @@
         public boolean accept(Bundle options) {
             // Make sure the options are unparcellable by the FW. (e.g. not containing unknown
             // classes.)
+            if (!isCallerValid()) {
+                throw new SecurityException("Calling uid mismatch");
+            }
             Intent extras = null;
             if (options != null) {
                 try {
@@ -126,8 +144,8 @@
         private PinShortcutRequestInner(ShortcutRequestPinProcessor processor,
                 ShortcutInfo shortcutOriginal, ShortcutInfo shortcutForLauncher,
                 IntentSender resultIntent,
-                String launcherPackage, int launcherUserId, boolean preExisting) {
-            super(processor, resultIntent);
+                String launcherPackage, int launcherUserId, int launcherUid, boolean preExisting) {
+            super(processor, resultIntent, launcherUid);
             this.shortcutOriginal = shortcutOriginal;
             this.shortcutForLauncher = shortcutForLauncher;
             this.launcherPackage = launcherPackage;
@@ -157,6 +175,7 @@
     /**
      * Handle {@link android.content.pm.ShortcutManager#requestPinShortcut)} and
      * {@link android.appwidget.AppWidgetManager#requestPinAppWidget}.
+     * In this flow the PinItemRequest is delivered directly to the default launcher app.
      * One of {@param inShortcut} and {@param inAppWidget} is always non-null and the other is
      * always null.
      */
@@ -184,9 +203,13 @@
         // Next, validate the incoming shortcut, etc.
         final PinItemRequest request;
         if (inShortcut != null) {
-            request = requestPinShortcutLocked(inShortcut, resultIntent, confirmActivity);
+            request = requestPinShortcutLocked(inShortcut, resultIntent, confirmActivity,
+                    true /* ignoreIfAlreadyPinned */);
         } else {
-            request = new PinItemRequest(inAppWidget, new PinItemRequestInner(this, resultIntent));
+            int launcherUid = mService.injectGetPackageUid(
+                    confirmActivity.first.getPackageName(), launcherUserId);
+            request = new PinItemRequest(inAppWidget,
+                    new PinItemRequestInner(this, resultIntent, launcherUid));
         }
 
         if (request == null) {
@@ -197,10 +220,41 @@
     }
 
     /**
+     * Handle {@link android.content.pm.ShortcutManager#createShortcutResultIntent(ShortcutInfo)}.
+     * In this flow the PinItemRequest is delivered to the caller app. Its the app's responsibility
+     * to send it to the Launcher app (via {@link android.app.Activity#setResult(int, Intent)}).
+     */
+    public Intent createShortcutResultIntent(@NonNull ShortcutInfo inShortcut, int userId) {
+        // Find the default launcher activity
+        final int launcherUserId = mService.getParentOrSelfUserId(userId);
+        final ComponentName defaultLauncher = mService.getDefaultLauncher(launcherUserId);
+        if (defaultLauncher == null) {
+            Log.e(TAG, "Default launcher not found.");
+            return null;
+        }
+
+        // Make sure the launcher user is unlocked. (it's always the parent profile, so should
+        // really be unlocked here though.)
+        mService.throwIfUserLockedL(launcherUserId);
+
+        // Next, validate the incoming shortcut, etc.
+        PinItemRequest request = requestPinShortcutLocked(inShortcut, null,
+                Pair.create(defaultLauncher, launcherUserId), false /* ignoreIfAlreadyPinned */);
+        if (request == null) {
+            return null;
+        }
+        return new Intent().putExtra(LauncherApps.EXTRA_PIN_ITEM_REQUEST, request);
+    }
+
+    /**
      * Handle {@link android.content.pm.ShortcutManager#requestPinShortcut)}.
+     *
+     * @param ignoreIfAlreadyPinned if true and the {@param inShortcut} is already pinned for
+     *                              {@param confirmActivity}, null is returned instead.
      */
     private PinItemRequest requestPinShortcutLocked(ShortcutInfo inShortcut,
-            IntentSender resultIntent, Pair<ComponentName, Integer> confirmActivity) {
+            IntentSender resultIntent, Pair<ComponentName, Integer> confirmActivity,
+            boolean ignoreIfAlreadyPinned) {
         final ShortcutPackage ps = mService.getPackageShortcutsForPublisherLocked(
                 inShortcut.getPackage(), inShortcut.getUserId());
 
@@ -221,9 +275,10 @@
         if (existsAlready) {
             validateExistingShortcut(existing);
 
+            final boolean isAlreadyPinned = mService.getLauncherShortcutsLocked(
+                    launcherPackage, existing.getUserId(), launcherUserId).hasPinned(existing);
             // See if it's already pinned.
-            if (mService.getLauncherShortcutsLocked(
-                    launcherPackage, existing.getUserId(), launcherUserId).hasPinned(existing)) {
+            if (ignoreIfAlreadyPinned && isAlreadyPinned) {
                 Log.i(TAG, "Launcher's already pinning shortcut " + existing.getId()
                         + " for package " + existing.getPackage());
                 return null;
@@ -233,8 +288,10 @@
             // Note this will remove the intent and icons.
             shortcutForLauncher = existing.clone(ShortcutInfo.CLONE_REMOVE_FOR_LAUNCHER);
 
-            // FLAG_PINNED is still set, if it's pinned by other launchers.
-            shortcutForLauncher.clearFlags(ShortcutInfo.FLAG_PINNED);
+            if (!isAlreadyPinned) {
+                // FLAG_PINNED is still set, if it's pinned by other launchers.
+                shortcutForLauncher.clearFlags(ShortcutInfo.FLAG_PINNED);
+            }
         } else {
             // If the shortcut has no default activity, try to set the main activity.
             // But in the request-pin case, it's optional, so it's okay even if the caller
@@ -264,7 +321,9 @@
         // Create a request object.
         final PinShortcutRequestInner inner =
                 new PinShortcutRequestInner(this, inShortcut, shortcutForLauncher, resultIntent,
-                        launcherPackage, launcherUserId, existsAlready);
+                        launcherPackage, launcherUserId,
+                        mService.injectGetPackageUid(launcherPackage, launcherUserId),
+                        existsAlready);
 
         return new PinItemRequest(shortcutForLauncher, inner);
     }
@@ -327,6 +386,10 @@
         mService.injectSendIntentSender(intent, extras);
     }
 
+    public boolean isCallerUid(int uid) {
+        return uid == mService.injectBinderCallingUid();
+    }
+
     /**
      * The last step of the "request pin shortcut" flow.  Called when the launcher accepted a
      * request.
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index a890526..ae709fe 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1529,7 +1529,7 @@
         if (UserHandle.getUserId(callingUid) != userId) {
             throw new SecurityException("Invalid user-ID");
         }
-        if (injectGetPackageUid(packageName, userId) == injectBinderCallingUid()) {
+        if (injectGetPackageUid(packageName, userId) == callingUid) {
             return; // Caller is valid.
         }
         throw new SecurityException("Calling package name mismatch");
@@ -1854,6 +1854,25 @@
         return requestPinItem(packageName, userId, shortcut, null, resultIntent);
     }
 
+    @Override
+    public Intent createShortcutResultIntent(String packageName, ShortcutInfo shortcut, int userId)
+            throws RemoteException {
+        Preconditions.checkNotNull(shortcut);
+        Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled");
+        verifyCaller(packageName, userId);
+
+        final Intent ret;
+        synchronized (mLock) {
+            throwIfUserLockedL(userId);
+
+            // Send request to the launcher, if supported.
+            ret = mShortcutRequestPinProcessor.createShortcutResultIntent(shortcut, userId);
+        }
+
+        verifyStates();
+        return ret;
+    }
+
     /**
      * Handles {@link #requestPinShortcut} and {@link ShortcutServiceInternal#requestPinAppWidget}.
      * After validating the caller, it passes the request to {@link #mShortcutRequestPinProcessor}.
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 9b47beb..e646ffc 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -67,6 +67,7 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManager.EnforcingUser;
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.os.storage.StorageManager;
@@ -118,6 +119,7 @@
 import java.io.PrintWriter;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 
@@ -162,7 +164,11 @@
     private static final String TAG_USER = "user";
     private static final String TAG_RESTRICTIONS = "restrictions";
     private static final String TAG_DEVICE_POLICY_RESTRICTIONS = "device_policy_restrictions";
+    private static final String TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS =
+            "device_policy_global_restrictions";
+    /** Legacy name for device owner id tag. */
     private static final String TAG_GLOBAL_RESTRICTION_OWNER_ID = "globalRestrictionOwnerUserId";
+    private static final String TAG_DEVICE_OWNER_USER_ID = "deviceOwnerUserId";
     private static final String TAG_ENTRY = "entry";
     private static final String TAG_VALUE = "value";
     private static final String TAG_SEED_ACCOUNT_OPTIONS = "seedAccountOptions";
@@ -202,7 +208,7 @@
     @VisibleForTesting
     static final int MAX_RECENTLY_REMOVED_IDS_SIZE = 100;
 
-    private static final int USER_VERSION = 6;
+    private static final int USER_VERSION = 7;
 
     private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
 
@@ -267,7 +273,7 @@
 
     /**
      * User restrictions set via UserManager.  This doesn't include restrictions set by
-     * device owner / profile owners.
+     * device owner / profile owners. Only non-empty restriction bundles are stored.
      *
      * DO NOT Change existing {@link Bundle} in it.  When changing a restriction for a user,
      * a new {@link Bundle} should always be created and set.  This is because a {@link Bundle}
@@ -305,20 +311,21 @@
 
     /**
      * User restrictions set by {@link com.android.server.devicepolicy.DevicePolicyManagerService}
-     * that should be applied to all users, including guests.
+     * that should be applied to all users, including guests. Only non-empty restriction bundles are
+     * stored.
      */
     @GuardedBy("mRestrictionsLock")
-    private Bundle mDevicePolicyGlobalUserRestrictions;
+    private final SparseArray<Bundle> mDevicePolicyGlobalUserRestrictions = new SparseArray<>();
 
     /**
      * Id of the user that set global restrictions.
      */
     @GuardedBy("mRestrictionsLock")
-    private int mGlobalRestrictionOwnerUserId = UserHandle.USER_NULL;
+    private int mDeviceOwnerUserId = UserHandle.USER_NULL;
 
     /**
      * User restrictions set by {@link com.android.server.devicepolicy.DevicePolicyManagerService}
-     * for each user.
+     * for each user. Only non-empty restriction bundles are stored.
      */
     @GuardedBy("mRestrictionsLock")
     private final SparseArray<Bundle> mDevicePolicyLocalUserRestrictions = new SparseArray<>();
@@ -1176,39 +1183,36 @@
     }
 
     /**
-     * See {@link UserManagerInternal#setDevicePolicyUserRestrictions(int, Bundle, Bundle)}
+     * See {@link UserManagerInternal#setDevicePolicyUserRestrictions}
      */
-    void setDevicePolicyUserRestrictionsInner(int userId, @NonNull Bundle local,
-            @Nullable Bundle global) {
-        Preconditions.checkNotNull(local);
-        boolean globalChanged = false;
-        boolean localChanged;
+    private void setDevicePolicyUserRestrictionsInner(int userId, @Nullable Bundle restrictions,
+            boolean isDeviceOwner, int cameraRestrictionScope) {
+        final Bundle global = new Bundle();
+        final Bundle local = new Bundle();
+
+        // Sort restrictions into local and global ensuring they don't overlap.
+        UserRestrictionsUtils.sortToGlobalAndLocal(restrictions, isDeviceOwner,
+                cameraRestrictionScope, global, local);
+
+        boolean globalChanged, localChanged;
         synchronized (mRestrictionsLock) {
-            if (global != null) {
-                // Update global.
-                globalChanged = !UserRestrictionsUtils.areEqual(
-                        mDevicePolicyGlobalUserRestrictions, global);
-                if (globalChanged) {
-                    mDevicePolicyGlobalUserRestrictions = global;
-                }
+            // Update global and local restrictions if they were changed.
+            globalChanged = updateRestrictionsIfNeededLR(
+                    userId, global, mDevicePolicyGlobalUserRestrictions);
+            localChanged = updateRestrictionsIfNeededLR(
+                    userId, local, mDevicePolicyLocalUserRestrictions);
+
+            if (isDeviceOwner) {
                 // Remember the global restriction owner userId to be able to make a distinction
                 // in getUserRestrictionSource on who set local policies.
-                mGlobalRestrictionOwnerUserId = userId;
+                mDeviceOwnerUserId = userId;
             } else {
-                if (mGlobalRestrictionOwnerUserId == userId) {
+                if (mDeviceOwnerUserId == userId) {
                     // When profile owner sets restrictions it passes null global bundle and we
                     // reset global restriction owner userId.
                     // This means this user used to have DO, but now the DO is gone and the user
                     // instead has PO.
-                    mGlobalRestrictionOwnerUserId = UserHandle.USER_NULL;
-                }
-            }
-            {
-                // Update local.
-                final Bundle prev = mDevicePolicyLocalUserRestrictions.get(userId);
-                localChanged = !UserRestrictionsUtils.areEqual(prev, local);
-                if (localChanged) {
-                    mDevicePolicyLocalUserRestrictions.put(userId, local);
+                    mDeviceOwnerUserId = UserHandle.USER_NULL;
                 }
             }
         }
@@ -1220,12 +1224,9 @@
         }
         // Don't call them within the mRestrictionsLock.
         synchronized (mPackagesLock) {
-            if (localChanged) {
+            if (localChanged || globalChanged) {
                 writeUserLP(getUserDataNoChecks(userId));
             }
-            if (globalChanged) {
-                writeUserListLP();
-            }
         }
 
         synchronized (mRestrictionsLock) {
@@ -1237,11 +1238,30 @@
         }
     }
 
+    /**
+     * Updates restriction bundle for a given user in a given restriction array. If new bundle is
+     * empty, record is removed from the array.
+     * @return whether restrictions bundle is different from the old one.
+     */
+    private boolean updateRestrictionsIfNeededLR(int userId, @Nullable Bundle restrictions,
+            SparseArray<Bundle> restrictionsArray) {
+        final boolean changed =
+                !UserRestrictionsUtils.areEqual(restrictionsArray.get(userId), restrictions);
+        if (changed) {
+            if (!UserRestrictionsUtils.isEmpty(restrictions)) {
+                restrictionsArray.put(userId, restrictions);
+            } else {
+                restrictionsArray.delete(userId);
+            }
+        }
+        return changed;
+    }
+
     @GuardedBy("mRestrictionsLock")
     private Bundle computeEffectiveUserRestrictionsLR(int userId) {
         final Bundle baseRestrictions =
                 UserRestrictionsUtils.nonNull(mBaseUserRestrictions.get(userId));
-        final Bundle global = mDevicePolicyGlobalUserRestrictions;
+        final Bundle global = UserRestrictionsUtils.mergeAll(mDevicePolicyGlobalUserRestrictions);
         final Bundle local = mDevicePolicyLocalUserRestrictions.get(userId);
 
         if (UserRestrictionsUtils.isEmpty(global) && UserRestrictionsUtils.isEmpty(local)) {
@@ -1299,39 +1319,58 @@
      */
     @Override
     public int getUserRestrictionSource(String restrictionKey, int userId) {
-        checkManageUsersPermission("getUserRestrictionSource");
+        List<EnforcingUser> enforcingUsers = getUserRestrictionSources(restrictionKey,  userId);
+        // Get "bitwise or" of restriction sources for all enforcing users.
         int result = UserManager.RESTRICTION_NOT_SET;
+        for (int i = enforcingUsers.size() - 1; i >= 0; i--) {
+            result |= enforcingUsers.get(i).getUserRestrictionSource();
+        }
+        return result;
+    }
+
+    @Override
+    public List<EnforcingUser> getUserRestrictionSources(
+            String restrictionKey, @UserIdInt int userId) {
+        checkManageUsersPermission("getUserRestrictionSource");
 
         // Shortcut for the most common case
         if (!hasUserRestriction(restrictionKey, userId)) {
-            return result;
+            return Collections.emptyList();
         }
 
+        final List<EnforcingUser> result = new ArrayList<>();
+
+        // Check if it is base restriction.
         if (hasBaseUserRestriction(restrictionKey, userId)) {
-            result |= UserManager.RESTRICTION_SOURCE_SYSTEM;
+            result.add(new EnforcingUser(
+                    UserHandle.USER_NULL, UserManager.RESTRICTION_SOURCE_SYSTEM));
         }
 
-        synchronized(mRestrictionsLock) {
-            Bundle localRestrictions = mDevicePolicyLocalUserRestrictions.get(userId);
-            if (!UserRestrictionsUtils.isEmpty(localRestrictions)
-                    && localRestrictions.getBoolean(restrictionKey)) {
-                // Local restrictions may have been set by device owner the userId of which is
-                // stored in mGlobalRestrictionOwnerUserId.
-                if (mGlobalRestrictionOwnerUserId == userId) {
-                    result |= UserManager.RESTRICTION_SOURCE_DEVICE_OWNER;
-                } else {
-                    result |= UserManager.RESTRICTION_SOURCE_PROFILE_OWNER;
+        synchronized (mRestrictionsLock) {
+            // Check if it is set by profile owner.
+            Bundle profileOwnerRestrictions = mDevicePolicyLocalUserRestrictions.get(userId);
+            if (UserRestrictionsUtils.contains(profileOwnerRestrictions, restrictionKey)) {
+                result.add(getEnforcingUserLocked(userId));
+            }
+
+            // Iterate over all users who enforce global restrictions.
+            for (int i = mDevicePolicyGlobalUserRestrictions.size() - 1; i >= 0; i--) {
+                Bundle globalRestrictions = mDevicePolicyGlobalUserRestrictions.valueAt(i);
+                int profileUserId = mDevicePolicyGlobalUserRestrictions.keyAt(i);
+                if (UserRestrictionsUtils.contains(globalRestrictions, restrictionKey)) {
+                    result.add(getEnforcingUserLocked(profileUserId));
                 }
             }
-            if (!UserRestrictionsUtils.isEmpty(mDevicePolicyGlobalUserRestrictions)
-                    && mDevicePolicyGlobalUserRestrictions.getBoolean(restrictionKey)) {
-                result |= UserManager.RESTRICTION_SOURCE_DEVICE_OWNER;
-            }
         }
-
         return result;
     }
 
+    private EnforcingUser getEnforcingUserLocked(@UserIdInt int userId) {
+        int source = mDeviceOwnerUserId == userId ? UserManager.RESTRICTION_SOURCE_DEVICE_OWNER
+                : UserManager.RESTRICTION_SOURCE_PROFILE_OWNER;
+        return new EnforcingUser(userId, source);
+    }
+
     /**
      * @return UserRestrictions that are in effect currently.  This always returns a new
      * {@link Bundle}.
@@ -1374,28 +1413,26 @@
      * Optionally updating user restrictions, calculate the effective user restrictions and also
      * propagate to other services and system settings.
      *
-     * @param newRestrictions User restrictions to set.
+     * @param newBaseRestrictions User restrictions to set.
      *      If null, will not update user restrictions and only does the propagation.
      * @param userId target user ID.
      */
     @GuardedBy("mRestrictionsLock")
     private void updateUserRestrictionsInternalLR(
-            @Nullable Bundle newRestrictions, int userId) {
-
+            @Nullable Bundle newBaseRestrictions, int userId) {
         final Bundle prevAppliedRestrictions = UserRestrictionsUtils.nonNull(
                 mAppliedUserRestrictions.get(userId));
 
         // Update base restrictions.
-        if (newRestrictions != null) {
-            // If newRestrictions == the current one, it's probably a bug.
+        if (newBaseRestrictions != null) {
+            // If newBaseRestrictions == the current one, it's probably a bug.
             final Bundle prevBaseRestrictions = mBaseUserRestrictions.get(userId);
 
-            Preconditions.checkState(prevBaseRestrictions != newRestrictions);
+            Preconditions.checkState(prevBaseRestrictions != newBaseRestrictions);
             Preconditions.checkState(mCachedEffectiveUserRestrictions.get(userId)
-                    != newRestrictions);
+                    != newBaseRestrictions);
 
-            if (!UserRestrictionsUtils.areEqual(prevBaseRestrictions, newRestrictions)) {
-                mBaseUserRestrictions.put(userId, newRestrictions);
+            if (updateRestrictionsIfNeededLR(userId, newBaseRestrictions, mBaseUserRestrictions)) {
                 scheduleWriteUser(getUserDataNoChecks(userId));
             }
         }
@@ -1523,7 +1560,7 @@
             return false;
         }
         // Limit number of managed profiles that can be created
-        final int managedProfilesCount = getProfiles(userId, true).size() - 1;
+        final int managedProfilesCount = getProfiles(userId, false).size() - 1;
         final int profilesRemovedCount = managedProfilesCount > 0 && allowedToRemoveOne ? 1 : 0;
         if (managedProfilesCount - profilesRemovedCount >= getMaxManagedProfiles()) {
             return false;
@@ -1746,7 +1783,9 @@
                 }
             }
 
-            final Bundle newDevicePolicyGlobalUserRestrictions = new Bundle();
+            // Pre-O global user restriction were stored as a single bundle (as opposed to per-user
+            // currently), take care of it in case of upgrade.
+            Bundle oldDevicePolicyGlobalUserRestrictions = null;
 
             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
                 if (type == XmlPullParser.START_TAG) {
@@ -1771,29 +1810,30 @@
                             if (type == XmlPullParser.START_TAG) {
                                 if (parser.getName().equals(TAG_RESTRICTIONS)) {
                                     synchronized (mGuestRestrictions) {
-                                        UserRestrictionsUtils
-                                                .readRestrictions(parser, mGuestRestrictions);
+                                        mGuestRestrictions.putAll(
+                                                UserRestrictionsUtils.readRestrictions(parser));
                                     }
                                 }
                                 break;
                             }
                         }
-                    } else if (name.equals(TAG_DEVICE_POLICY_RESTRICTIONS)) {
-                        UserRestrictionsUtils.readRestrictions(parser,
-                                newDevicePolicyGlobalUserRestrictions);
-                    } else if (name.equals(TAG_GLOBAL_RESTRICTION_OWNER_ID)) {
+                    } else if (name.equals(TAG_DEVICE_OWNER_USER_ID)
+                            // Legacy name, should only be encountered when upgrading from pre-O.
+                            || name.equals(TAG_GLOBAL_RESTRICTION_OWNER_ID)) {
                         String ownerUserId = parser.getAttributeValue(null, ATTR_ID);
                         if (ownerUserId != null) {
-                            mGlobalRestrictionOwnerUserId = Integer.parseInt(ownerUserId);
+                            mDeviceOwnerUserId = Integer.parseInt(ownerUserId);
                         }
+                    } else if (name.equals(TAG_DEVICE_POLICY_RESTRICTIONS)) {
+                        // Should only happen when upgrading from pre-O (version < 7).
+                        oldDevicePolicyGlobalUserRestrictions =
+                                UserRestrictionsUtils.readRestrictions(parser);
                     }
                 }
             }
-            synchronized (mRestrictionsLock) {
-                mDevicePolicyGlobalUserRestrictions = newDevicePolicyGlobalUserRestrictions;
-            }
+
             updateUserIds();
-            upgradeIfNecessaryLP();
+            upgradeIfNecessaryLP(oldDevicePolicyGlobalUserRestrictions);
         } catch (IOException | XmlPullParserException e) {
             fallbackToSingleUserLP();
         } finally {
@@ -1803,8 +1843,9 @@
 
     /**
      * Upgrade steps between versions, either for fixing bugs or changing the data format.
+     * @param oldGlobalUserRestrictions Pre-O global device policy restrictions.
      */
-    private void upgradeIfNecessaryLP() {
+    private void upgradeIfNecessaryLP(Bundle oldGlobalUserRestrictions) {
         final int originalVersion = mUserVersion;
         int userVersion = mUserVersion;
         if (userVersion < 1) {
@@ -1855,6 +1896,23 @@
             userVersion = 6;
         }
 
+        if (userVersion < 7) {
+            // Previously only one user could enforce global restrictions, now it is per-user.
+            synchronized (mRestrictionsLock) {
+                if (!UserRestrictionsUtils.isEmpty(oldGlobalUserRestrictions)
+                        && mDeviceOwnerUserId != UserHandle.USER_NULL) {
+                    mDevicePolicyGlobalUserRestrictions.put(
+                            mDeviceOwnerUserId, oldGlobalUserRestrictions);
+                }
+                // ENSURE_VERIFY_APPS is now enforced globally even if put by profile owner, so move
+                // it from local to global bundle for all users who set it.
+                UserRestrictionsUtils.moveRestriction(UserManager.ENSURE_VERIFY_APPS,
+                        mDevicePolicyLocalUserRestrictions, mDevicePolicyGlobalUserRestrictions
+                );
+            }
+            userVersion = 7;
+        }
+
         if (userVersion < USER_VERSION) {
             Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
                     + USER_VERSION);
@@ -1893,8 +1951,10 @@
             Log.e(LOG_TAG, "Couldn't find resource: config_defaultFirstUserRestrictions", e);
         }
 
-        synchronized (mRestrictionsLock) {
-            mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
+        if (!restrictions.isEmpty()) {
+            synchronized (mRestrictionsLock) {
+                mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
+            }
         }
 
         updateUserIds();
@@ -2004,6 +2064,9 @@
             UserRestrictionsUtils.writeRestrictions(serializer,
                     mDevicePolicyLocalUserRestrictions.get(userInfo.id),
                     TAG_DEVICE_POLICY_RESTRICTIONS);
+            UserRestrictionsUtils.writeRestrictions(serializer,
+                    mDevicePolicyGlobalUserRestrictions.get(userInfo.id),
+                    TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS);
         }
 
         if (userData.account != null) {
@@ -2057,13 +2120,9 @@
                         .writeRestrictions(serializer, mGuestRestrictions, TAG_RESTRICTIONS);
             }
             serializer.endTag(null, TAG_GUEST_RESTRICTIONS);
-            synchronized (mRestrictionsLock) {
-                UserRestrictionsUtils.writeRestrictions(serializer,
-                        mDevicePolicyGlobalUserRestrictions, TAG_DEVICE_POLICY_RESTRICTIONS);
-            }
-            serializer.startTag(null, TAG_GLOBAL_RESTRICTION_OWNER_ID);
-            serializer.attribute(null, ATTR_ID, Integer.toString(mGlobalRestrictionOwnerUserId));
-            serializer.endTag(null, TAG_GLOBAL_RESTRICTION_OWNER_ID);
+            serializer.startTag(null, TAG_DEVICE_OWNER_USER_ID);
+            serializer.attribute(null, ATTR_ID, Integer.toString(mDeviceOwnerUserId));
+            serializer.endTag(null, TAG_DEVICE_OWNER_USER_ID);
             int[] userIdsToWrite;
             synchronized (mUsersLock) {
                 userIdsToWrite = new int[mUsers.size()];
@@ -2125,8 +2184,9 @@
         String seedAccountName = null;
         String seedAccountType = null;
         PersistableBundle seedAccountOptions = null;
-        Bundle baseRestrictions = new Bundle();
-        Bundle localRestrictions = new Bundle();
+        Bundle baseRestrictions = null;
+        Bundle localRestrictions = null;
+        Bundle globalRestrictions = null;
 
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(is, StandardCharsets.UTF_8.name());
@@ -2187,9 +2247,11 @@
                         name = parser.getText();
                     }
                 } else if (TAG_RESTRICTIONS.equals(tag)) {
-                    UserRestrictionsUtils.readRestrictions(parser, baseRestrictions);
+                    baseRestrictions = UserRestrictionsUtils.readRestrictions(parser);
                 } else if (TAG_DEVICE_POLICY_RESTRICTIONS.equals(tag)) {
-                    UserRestrictionsUtils.readRestrictions(parser, localRestrictions);
+                    localRestrictions = UserRestrictionsUtils.readRestrictions(parser);
+                } else if (TAG_DEVICE_POLICY_GLOBAL_RESTRICTIONS.equals(tag)) {
+                    globalRestrictions = UserRestrictionsUtils.readRestrictions(parser);
                 } else if (TAG_ACCOUNT.equals(tag)) {
                     type = parser.next();
                     if (type == XmlPullParser.TEXT) {
@@ -2224,8 +2286,15 @@
         userData.seedAccountOptions = seedAccountOptions;
 
         synchronized (mRestrictionsLock) {
-            mBaseUserRestrictions.put(id, baseRestrictions);
-            mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
+            if (baseRestrictions != null) {
+                mBaseUserRestrictions.put(id, baseRestrictions);
+            }
+            if (localRestrictions != null) {
+                mDevicePolicyLocalUserRestrictions.put(id, localRestrictions);
+            }
+            if (globalRestrictions != null) {
+                mDevicePolicyGlobalUserRestrictions.put(id, globalRestrictions);
+            }
         }
         return userData;
     }
@@ -2731,6 +2800,10 @@
             mAppliedUserRestrictions.remove(userHandle);
             mCachedEffectiveUserRestrictions.remove(userHandle);
             mDevicePolicyLocalUserRestrictions.remove(userHandle);
+            if (mDevicePolicyGlobalUserRestrictions.get(userHandle) != null) {
+                mDevicePolicyGlobalUserRestrictions.remove(userHandle);
+                applyUserRestrictionsForAllUsersLR();
+            }
         }
         // Update the user list
         synchronized (mPackagesLock) {
@@ -3420,6 +3493,9 @@
                     synchronized (mRestrictionsLock) {
                         UserRestrictionsUtils.dumpRestrictions(
                                 pw, "      ", mBaseUserRestrictions.get(userInfo.id));
+                        pw.println("    Device policy global restrictions:");
+                        UserRestrictionsUtils.dumpRestrictions(
+                                pw, "      ", mDevicePolicyGlobalUserRestrictions.get(userInfo.id));
                         pw.println("    Device policy local restrictions:");
                         UserRestrictionsUtils.dumpRestrictions(
                                 pw, "      ", mDevicePolicyLocalUserRestrictions.get(userInfo.id));
@@ -3448,13 +3524,7 @@
                 }
             }
             pw.println();
-            pw.println("  Device policy global restrictions:");
-            synchronized (mRestrictionsLock) {
-                UserRestrictionsUtils
-                        .dumpRestrictions(pw, "    ", mDevicePolicyGlobalUserRestrictions);
-            }
-            pw.println();
-            pw.println("  Global restrictions owner id:" + mGlobalRestrictionOwnerUserId);
+            pw.println("  Device owner id:" + mDeviceOwnerUserId);
             pw.println();
             pw.println("  Guest restrictions:");
             synchronized (mGuestRestrictions) {
@@ -3508,10 +3578,10 @@
 
     private class LocalService extends UserManagerInternal {
         @Override
-        public void setDevicePolicyUserRestrictions(int userId, @NonNull Bundle localRestrictions,
-                @Nullable Bundle globalRestrictions) {
-            UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, localRestrictions,
-                    globalRestrictions);
+        public void setDevicePolicyUserRestrictions(int userId, @Nullable Bundle restrictions,
+                boolean isDeviceOwner, int cameraRestrictionScope) {
+            UserManagerService.this.setDevicePolicyUserRestrictionsInner(userId, restrictions,
+                isDeviceOwner, cameraRestrictionScope);
         }
 
         @Override
@@ -3525,8 +3595,10 @@
         public void setBaseUserRestrictionsByDpmsForMigration(
                 int userId, Bundle baseRestrictions) {
             synchronized (mRestrictionsLock) {
-                mBaseUserRestrictions.put(userId, new Bundle(baseRestrictions));
-                invalidateEffectiveUserRestrictionsLR(userId);
+                if (updateRestrictionsIfNeededLR(
+                        userId, new Bundle(baseRestrictions), mBaseUserRestrictions)) {
+                    invalidateEffectiveUserRestrictionsLR(userId);
+                }
             }
 
             final UserData userData = getUserDataNoChecks(userId);
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index f5b8669..d301463 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -30,11 +30,13 @@
 import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.service.persistentdata.PersistentDataBlockManager;
 import android.telephony.SubscriptionInfo;
 import android.telephony.SubscriptionManager;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlSerializer;
@@ -117,9 +119,10 @@
     );
 
     /**
-     * User restrictions that can not be set by profile owners.
+     * User restrictions that cannot be set by profile owners of secondary users. When set by DO
+     * they will be applied to all users.
      */
-    private static final Set<String> DEVICE_OWNER_ONLY_RESTRICTIONS = Sets.newArraySet(
+    private static final Set<String> PRIMARY_USER_ONLY_RESTRICTIONS = Sets.newArraySet(
             UserManager.DISALLOW_BLUETOOTH,
             UserManager.DISALLOW_USB_FILE_TRANSFER,
             UserManager.DISALLOW_CONFIG_TETHERING,
@@ -163,6 +166,13 @@
             UserManager.DISALLOW_ADD_MANAGED_PROFILE
     );
 
+    /*
+     * Special user restrictions that are always applied to all users no matter who sets them.
+     */
+    private static final Set<String> PROFILE_GLOBAL_RESTRICTIONS = Sets.newArraySet(
+            UserManager.ENSURE_VERIFY_APPS
+    );
+
     /**
      * Throws {@link IllegalArgumentException} if the given restriction name is invalid.
      */
@@ -205,6 +215,12 @@
         }
     }
 
+    public static Bundle readRestrictions(XmlPullParser parser) {
+        final Bundle result = new Bundle();
+        readRestrictions(parser, result);
+        return result;
+    }
+
     /**
      * @return {@code in} itself when it's not null, or an empty bundle (which can writable).
      */
@@ -217,6 +233,14 @@
     }
 
     /**
+     * Returns {@code true} if given bundle is not null and contains {@code true} for a given
+     * restriction.
+     */
+    public static boolean contains(@Nullable Bundle in, String restriction) {
+        return in != null && in.getBoolean(restriction);
+    }
+
+    /**
      * Creates a copy of the {@code in} Bundle.  If {@code in} is null, it'll return an empty
      * bundle.
      *
@@ -241,6 +265,22 @@
     }
 
     /**
+     * Merges a sparse array of restrictions bundles into one.
+     */
+    @Nullable
+    public static Bundle mergeAll(SparseArray<Bundle> restrictions) {
+        if (restrictions.size() == 0) {
+            return null;
+        } else {
+            final Bundle result = new Bundle();
+            for (int i = 0; i < restrictions.size(); i++) {
+                merge(result, restrictions.valueAt(i));
+            }
+            return result;
+        }
+    }
+
+    /**
      * @return true if a restriction is settable by device owner.
      */
     public static boolean canDeviceOwnerChange(String restriction) {
@@ -254,7 +294,7 @@
     public static boolean canProfileOwnerChange(String restriction, int userId) {
         return !IMMUTABLE_BY_OWNERS.contains(restriction)
                 && !(userId != UserHandle.USER_SYSTEM
-                    && DEVICE_OWNER_ONLY_RESTRICTIONS.contains(restriction));
+                    && PRIMARY_USER_ONLY_RESTRICTIONS.contains(restriction));
     }
 
     /**
@@ -269,8 +309,15 @@
      * Takes restrictions that can be set by device owner, and sort them into what should be applied
      * globally and what should be applied only on the current user.
      */
-    public static void sortToGlobalAndLocal(@Nullable Bundle in, @NonNull Bundle global,
-            @NonNull Bundle local) {
+    public static void sortToGlobalAndLocal(@Nullable Bundle in, boolean isDeviceOwner,
+            int cameraRestrictionScope,
+            @NonNull Bundle global, @NonNull Bundle local) {
+        // Camera restriction (as well as all others) goes to at most one bundle.
+        if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_GLOBALLY) {
+            global.putBoolean(UserManager.DISALLOW_CAMERA, true);
+        } else if (cameraRestrictionScope == UserManagerInternal.CAMERA_DISABLED_LOCALLY) {
+            local.putBoolean(UserManager.DISALLOW_CAMERA, true);
+        }
         if (in == null || in.size() == 0) {
             return;
         }
@@ -278,7 +325,7 @@
             if (!in.getBoolean(key)) {
                 continue;
             }
-            if (DEVICE_OWNER_ONLY_RESTRICTIONS.contains(key) || GLOBAL_RESTRICTIONS.contains(key)) {
+            if (isGlobal(isDeviceOwner, key)) {
                 global.putBoolean(key, true);
             } else {
                 local.putBoolean(key, true);
@@ -287,6 +334,15 @@
     }
 
     /**
+     * Whether given user restriction should be enforced globally.
+     */
+    private static boolean isGlobal(boolean isDeviceOwner, String key) {
+        return (isDeviceOwner &&
+                (PRIMARY_USER_ONLY_RESTRICTIONS.contains(key)|| GLOBAL_RESTRICTIONS.contains(key)))
+                || PROFILE_GLOBAL_RESTRICTIONS.contains(key);
+    }
+
+    /**
      * @return true if two Bundles contain the same user restriction.
      * A null bundle and an empty bundle are considered to be equal.
      */
@@ -485,4 +541,29 @@
             pw.println(prefix + "null");
         }
     }
+
+    /**
+     * Moves a particular restriction from one array of bundles to another, e.g. for all users.
+     */
+    public static void moveRestriction(String restrictionKey, SparseArray<Bundle> srcRestrictions,
+            SparseArray<Bundle> destRestrictions) {
+        for (int i = 0; i < srcRestrictions.size(); i++) {
+            int key = srcRestrictions.keyAt(i);
+            Bundle from = srcRestrictions.valueAt(i);
+            if (contains(from, restrictionKey)) {
+                from.remove(restrictionKey);
+                Bundle to = destRestrictions.get(key);
+                if (to == null) {
+                    to = new Bundle();
+                    destRestrictions.append(key, to);
+                }
+                to.putBoolean(restrictionKey, true);
+                // Don't keep empty bundles.
+                if (from.isEmpty()) {
+                    srcRestrictions.removeAt(i);
+                    i--;
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/policy/AccessibilityShortcutController.java b/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
new file mode 100644
index 0000000..133881a
--- /dev/null
+++ b/services/core/java/com/android/server/policy/AccessibilityShortcutController.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2012 Google Inc.
+ *
+ * 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.policy;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.database.ContentObserver;
+import android.media.AudioAttributes;
+import android.media.Ringtone;
+import android.media.RingtoneManager;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Slog;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
+
+import android.widget.Toast;
+import com.android.internal.R;
+
+import java.util.List;
+
+import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
+
+/**
+ * Class to help manage the accessibility shortcut
+ */
+public class AccessibilityShortcutController {
+    private static final String TAG = "AccessibilityShortcutController";
+
+    private final Context mContext;
+    private AlertDialog mAlertDialog;
+    private boolean mIsShortcutEnabled;
+    // Visible for testing
+    public FrameworkObjectProvider mFrameworkObjectProvider = new FrameworkObjectProvider();
+
+    public static String getTargetServiceComponentNameString(
+            Context context, int userId) {
+        final String currentShortcutServiceId = Settings.Secure.getStringForUser(
+                context.getContentResolver(), Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE,
+                userId);
+        if (currentShortcutServiceId != null) {
+            return currentShortcutServiceId;
+        }
+        return context.getString(R.string.config_defaultAccessibilityService);
+    }
+
+    public AccessibilityShortcutController(Context context, Handler handler) {
+        mContext = context;
+
+        // Keep track of state of shortcut
+        mContext.getContentResolver().registerContentObserver(
+                Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE),
+                false,
+                new ContentObserver(handler) {
+                    @Override
+                    public void onChange(boolean selfChange) {
+                        onSettingsChanged();
+                    }
+                },
+                UserHandle.USER_ALL);
+        updateShortcutEnabled();
+    }
+
+    public boolean isAccessibilityShortcutAvailable() {
+        return mIsShortcutEnabled;
+    }
+
+    public void onSettingsChanged() {
+        updateShortcutEnabled();
+    }
+
+    /**
+     * Called when the accessibility shortcut is activated
+     */
+    public void performAccessibilityShortcut() {
+        Slog.d(TAG, "Accessibility shortcut activated");
+        final ContentResolver cr = mContext.getContentResolver();
+        final int userId = ActivityManager.getCurrentUser();
+        final int dialogAlreadyShown = Settings.Secure.getIntForUser(
+                cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
+        final Ringtone tone =
+                RingtoneManager.getRingtone(mContext, Settings.System.DEFAULT_NOTIFICATION_URI);
+        if (tone != null) {
+            tone.setAudioAttributes(new AudioAttributes.Builder()
+                .setUsage(AudioAttributes.USAGE_NOTIFICATION_EVENT)
+                .build());
+            tone.play();
+        }
+        if (dialogAlreadyShown == 0) {
+            // The first time, we show a warning rather than toggle the service to give the user a
+            // chance to turn off this feature before stuff gets enabled.
+            mAlertDialog = createShortcutWarningDialog(userId);
+            if (mAlertDialog == null) {
+                return;
+            }
+            Window w = mAlertDialog.getWindow();
+            WindowManager.LayoutParams attr = w.getAttributes();
+            attr.type = TYPE_KEYGUARD_DIALOG;
+            w.setAttributes(attr);
+            mAlertDialog.show();
+            Settings.Secure.putIntForUser(
+                    cr, Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1, userId);
+        } else {
+            if (mAlertDialog != null) {
+                mAlertDialog.dismiss();
+                mAlertDialog = null;
+            }
+
+            // Show a toast alerting the user to what's happening
+            final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
+            if (serviceInfo == null) {
+                Slog.e(TAG, "Accessibility shortcut set to invalid service");
+                return;
+            }
+            String toastMessageFormatString = mContext.getString(isServiceEnabled(serviceInfo)
+                    ? R.string.accessibility_shortcut_disabling_service
+                    : R.string.accessibility_shortcut_enabling_service);
+            String toastMessage = String.format(toastMessageFormatString,
+                    serviceInfo.getResolveInfo()
+                            .loadLabel(mContext.getPackageManager()).toString());
+            mFrameworkObjectProvider.makeToastFromText(mContext, toastMessage, Toast.LENGTH_LONG)
+                    .show();
+
+            mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext)
+                    .performAccessibilityShortcut();
+        }
+    }
+
+    private void updateShortcutEnabled() {
+        mIsShortcutEnabled = !TextUtils.isEmpty(getTargetServiceComponentNameString(
+                mContext, UserHandle.myUserId()));
+    }
+
+    private AlertDialog createShortcutWarningDialog(int userId) {
+        final AccessibilityServiceInfo serviceInfo = getInfoForTargetService();
+
+        if (serviceInfo == null) {
+            return null;
+        }
+
+        final String warningMessage = String.format(
+                mContext.getString(R.string.accessibility_shortcut_toogle_warning),
+                serviceInfo.getResolveInfo().loadLabel(mContext.getPackageManager()).toString());
+        final AlertDialog alertDialog = mFrameworkObjectProvider.getAlertDialogBuilder(mContext)
+                .setTitle(R.string.accessibility_shortcut_warning_dialog_title)
+                .setMessage(warningMessage)
+                .setCancelable(false)
+                .setPositiveButton(R.string.leave_accessibility_shortcut_on, null)
+                .setNegativeButton(R.string.disable_accessibility_shortcut,
+                        (DialogInterface d, int which) -> {
+                            Settings.Secure.putStringForUser(mContext.getContentResolver(),
+                                    Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "",
+                                    userId);
+                        })
+                .setOnCancelListener((DialogInterface d) -> {
+                    // If canceled, treat as if the dialog has never been shown
+                    Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0, userId);
+                })
+                .create();
+        return alertDialog;
+    }
+
+    private AccessibilityServiceInfo getInfoForTargetService() {
+        final String currentShortcutServiceString = getTargetServiceComponentNameString(
+                mContext, UserHandle.myUserId());
+        if (currentShortcutServiceString == null) {
+            return null;
+        }
+        AccessibilityManager accessibilityManager =
+                mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext);
+        return accessibilityManager.getInstalledServiceInfoWithComponentName(
+                        ComponentName.unflattenFromString(currentShortcutServiceString));
+    }
+
+    private boolean isServiceEnabled(AccessibilityServiceInfo serviceInfo) {
+        AccessibilityManager accessibilityManager =
+                mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext);
+        return accessibilityManager.getEnabledAccessibilityServiceList(
+                AccessibilityServiceInfo.FEEDBACK_ALL_MASK).contains(serviceInfo);
+    }
+
+    // Class to allow mocking of static framework calls
+    public static class FrameworkObjectProvider {
+        public AccessibilityManager getAccessibilityManagerInstance(Context context) {
+            return AccessibilityManager.getInstance(context);
+        }
+
+        public AlertDialog.Builder getAlertDialogBuilder(Context context) {
+            return new AlertDialog.Builder(context);
+        }
+
+        public Toast makeToastFromText(Context context, CharSequence charSequence, int duration) {
+            return Toast.makeText(context, charSequence, duration);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/policy/EnableAccessibilityController.java b/services/core/java/com/android/server/policy/EnableAccessibilityController.java
deleted file mode 100644
index 6b203a9..0000000
--- a/services/core/java/com/android/server/policy/EnableAccessibilityController.java
+++ /dev/null
@@ -1,291 +0,0 @@
-/*
- * Copyright (C) 2012 Google Inc.
- *
- * 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.policy;
-
-import android.accessibilityservice.AccessibilityService;
-import android.accessibilityservice.AccessibilityServiceInfo;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
-import android.content.ComponentName;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.pm.ServiceInfo;
-import android.media.AudioManager;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
-import android.os.Handler;
-import android.os.Message;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.os.UserManager;
-import android.provider.Settings;
-import android.speech.tts.TextToSpeech;
-import android.util.Log;
-import android.util.MathUtils;
-import android.view.IWindowManager;
-import android.view.MotionEvent;
-import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
-import android.view.WindowManagerInternal;
-import android.view.accessibility.AccessibilityManager;
-import android.view.accessibility.IAccessibilityManager;
-
-import com.android.internal.R;
-import com.android.server.LocalServices;
-
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-
-public class EnableAccessibilityController {
-    private static final String TAG = "EnableAccessibilityController";
-
-    private static final int SPEAK_WARNING_DELAY_MILLIS = 2000;
-    private static final int ENABLE_ACCESSIBILITY_DELAY_MILLIS = 6000;
-
-    public static final int MESSAGE_SPEAK_WARNING = 1;
-    public static final int MESSAGE_SPEAK_ENABLE_CANCELED = 2;
-    public static final int MESSAGE_ENABLE_ACCESSIBILITY = 3;
-
-    private final Handler mHandler = new Handler() {
-        @Override
-        public void handleMessage(Message message) {
-            switch (message.what) {
-                case MESSAGE_SPEAK_WARNING: {
-                    String text = mContext.getString(R.string.continue_to_enable_accessibility);
-                    mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
-                } break;
-                case MESSAGE_SPEAK_ENABLE_CANCELED: {
-                    String text = mContext.getString(R.string.enable_accessibility_canceled);
-                    mTts.speak(text, TextToSpeech.QUEUE_FLUSH, null);
-                } break;
-                case MESSAGE_ENABLE_ACCESSIBILITY: {
-                    enableAccessibility();
-                    mTone.play();
-                    mTts.speak(mContext.getString(R.string.accessibility_enabled),
-                            TextToSpeech.QUEUE_FLUSH, null);
-                } break;
-            }
-        }
-    };
-
-    private final IAccessibilityManager mAccessibilityManager = IAccessibilityManager
-            .Stub.asInterface(ServiceManager.getService("accessibility"));
-
-
-    private final Context mContext;
-    private final Runnable mOnAccessibilityEnabledCallback;
-    private final UserManager mUserManager;
-    private final TextToSpeech mTts;
-    private final Ringtone mTone;
-
-    private final float mTouchSlop;
-
-    private boolean mDestroyed;
-    private boolean mCanceled;
-
-    private float mFirstPointerDownX;
-    private float mFirstPointerDownY;
-    private float mSecondPointerDownX;
-    private float mSecondPointerDownY;
-
-    public EnableAccessibilityController(Context context, Runnable onAccessibilityEnabledCallback) {
-        mContext = context;
-        mOnAccessibilityEnabledCallback = onAccessibilityEnabledCallback;
-        mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        mTts = new TextToSpeech(context, new TextToSpeech.OnInitListener() {
-            @Override
-            public void onInit(int status) {
-                if (mDestroyed) {
-                    mTts.shutdown();
-                }
-            }
-        });
-        mTone = RingtoneManager.getRingtone(context, Settings.System.DEFAULT_NOTIFICATION_URI);
-        mTone.setStreamType(AudioManager.STREAM_MUSIC);
-        mTouchSlop = context.getResources().getDimensionPixelSize(
-                R.dimen.accessibility_touch_slop);
-    }
-
-    public static boolean canEnableAccessibilityViaGesture(Context context) {
-        AccessibilityManager accessibilityManager = AccessibilityManager.getInstance(context);
-        // Accessibility is enabled and there is an enabled speaking
-        // accessibility service, then we have nothing to do.
-        if (accessibilityManager.isEnabled()
-                && !accessibilityManager.getEnabledAccessibilityServiceList(
-                        AccessibilityServiceInfo.FEEDBACK_SPOKEN).isEmpty()) {
-            return false;
-        }
-        // If the global gesture is enabled and there is a speaking service
-        // installed we are good to go, otherwise there is nothing to do.
-        return Settings.Global.getInt(context.getContentResolver(),
-                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1
-                && !getInstalledSpeakingAccessibilityServices(context).isEmpty();
-    }
-
-    public static List<AccessibilityServiceInfo> getInstalledSpeakingAccessibilityServices(
-            Context context) {
-        List<AccessibilityServiceInfo> services = new ArrayList<AccessibilityServiceInfo>();
-        services.addAll(AccessibilityManager.getInstance(context)
-                .getInstalledAccessibilityServiceList());
-        Iterator<AccessibilityServiceInfo> iterator = services.iterator();
-        while (iterator.hasNext()) {
-            AccessibilityServiceInfo service = iterator.next();
-            if ((service.feedbackType & AccessibilityServiceInfo.FEEDBACK_SPOKEN) == 0) {
-                iterator.remove();
-            }
-        }
-        return services;
-    }
-
-    public void onDestroy() {
-        mDestroyed = true;
-    }
-
-    public boolean onInterceptTouchEvent(MotionEvent event) {
-        if (event.getActionMasked() == MotionEvent.ACTION_POINTER_DOWN
-                && event.getPointerCount() == 2) {
-            mFirstPointerDownX = event.getX(0);
-            mFirstPointerDownY = event.getY(0);
-            mSecondPointerDownX = event.getX(1);
-            mSecondPointerDownY = event.getY(1);
-            mHandler.sendEmptyMessageDelayed(MESSAGE_SPEAK_WARNING,
-                    SPEAK_WARNING_DELAY_MILLIS);
-            mHandler.sendEmptyMessageDelayed(MESSAGE_ENABLE_ACCESSIBILITY,
-                   ENABLE_ACCESSIBILITY_DELAY_MILLIS);
-            return true;
-        }
-        return false;
-    }
-
-    public boolean onTouchEvent(MotionEvent event) {
-        final int pointerCount = event.getPointerCount();
-        final int action = event.getActionMasked();
-        if (mCanceled) {
-            if (action == MotionEvent.ACTION_UP) {
-                mCanceled = false;
-            }
-            return true;
-        }
-        switch (action) {
-            case MotionEvent.ACTION_POINTER_DOWN: {
-                if (pointerCount > 2) {
-                    cancel();
-                }
-            } break;
-            case MotionEvent.ACTION_MOVE: {
-                final float firstPointerMove = MathUtils.dist(event.getX(0),
-                        event.getY(0), mFirstPointerDownX, mFirstPointerDownY);
-                if (Math.abs(firstPointerMove) > mTouchSlop) {
-                    cancel();
-                }
-                final float secondPointerMove = MathUtils.dist(event.getX(1),
-                        event.getY(1), mSecondPointerDownX, mSecondPointerDownY);
-                if (Math.abs(secondPointerMove) > mTouchSlop) {
-                    cancel();
-                }
-            } break;
-            case MotionEvent.ACTION_POINTER_UP:
-            case MotionEvent.ACTION_CANCEL: {
-                cancel();
-            } break;
-        }
-        return true;
-    }
-
-    private void cancel() {
-        mCanceled = true;
-        if (mHandler.hasMessages(MESSAGE_SPEAK_WARNING)) {
-            mHandler.removeMessages(MESSAGE_SPEAK_WARNING);
-        } else if (mHandler.hasMessages(MESSAGE_ENABLE_ACCESSIBILITY)) {
-            mHandler.sendEmptyMessage(MESSAGE_SPEAK_ENABLE_CANCELED);
-        }
-        mHandler.removeMessages(MESSAGE_ENABLE_ACCESSIBILITY);
-    }
-
-    private void enableAccessibility() {
-        if (enableAccessibility(mContext)) {
-            mOnAccessibilityEnabledCallback.run();
-        }
-    }
-
-    public static boolean enableAccessibility(Context context) {
-        final IAccessibilityManager accessibilityManager = IAccessibilityManager
-                .Stub.asInterface(ServiceManager.getService("accessibility"));
-        final WindowManagerInternal windowManager = LocalServices.getService(
-                WindowManagerInternal.class);
-        final UserManager userManager = (UserManager) context.getSystemService(
-                Context.USER_SERVICE);
-        ComponentName componentName = getInstalledSpeakingAccessibilityServiceComponent(context);
-        if (componentName == null) {
-            return false;
-        }
-
-        boolean keyguardLocked = windowManager.isKeyguardLocked();
-        final boolean hasMoreThanOneUser = userManager.getUsers().size() > 1;
-        try {
-            if (!keyguardLocked || !hasMoreThanOneUser) {
-                final int userId = ActivityManager.getCurrentUser();
-                accessibilityManager.enableAccessibilityService(componentName, userId);
-            } else if (keyguardLocked) {
-                accessibilityManager.temporaryEnableAccessibilityStateUntilKeyguardRemoved(
-                        componentName, true /* enableTouchExploration */);
-            }
-        } catch (RemoteException e) {
-            Log.e(TAG, "cannot enable accessibilty: " + e);
-        }
-
-        return true;
-    }
-
-    public static void disableAccessibility(Context context) {
-        final IAccessibilityManager accessibilityManager = IAccessibilityManager
-                .Stub.asInterface(ServiceManager.getService("accessibility"));
-        ComponentName componentName = getInstalledSpeakingAccessibilityServiceComponent(context);
-        if (componentName == null) {
-            return;
-        }
-
-        final int userId = ActivityManager.getCurrentUser();
-        try {
-            accessibilityManager.disableAccessibilityService(componentName, userId);
-        } catch (RemoteException e) {
-            Log.e(TAG, "cannot disable accessibility " + e);
-        }
-    }
-
-    public static boolean isAccessibilityEnabled(Context context) {
-        final AccessibilityManager accessibilityManager =
-                context.getSystemService(AccessibilityManager.class);
-        List enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
-                AccessibilityServiceInfo.FEEDBACK_SPOKEN);
-        return enabledServices != null && !enabledServices.isEmpty();
-    }
-
-    @Nullable
-    public static ComponentName getInstalledSpeakingAccessibilityServiceComponent(
-            Context context) {
-        List<AccessibilityServiceInfo> services =
-                getInstalledSpeakingAccessibilityServices(context);
-        if (services.isEmpty()) {
-            return null;
-        }
-
-        ServiceInfo serviceInfo = services.get(0).getResolveInfo().serviceInfo;
-        return new ComponentName(serviceInfo.packageName, serviceInfo.name);
-    }
-}
diff --git a/services/core/java/com/android/server/policy/GlobalActions.java b/services/core/java/com/android/server/policy/GlobalActions.java
index d4adcc4..335a230 100644
--- a/services/core/java/com/android/server/policy/GlobalActions.java
+++ b/services/core/java/com/android/server/policy/GlobalActions.java
@@ -44,7 +44,6 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -59,12 +58,9 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.util.TypedValue;
-import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
-import android.view.ViewConfiguration;
 import android.view.ViewGroup;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
@@ -1194,21 +1190,14 @@
 
     private static final class GlobalActionsDialog extends Dialog implements DialogInterface {
         private final Context mContext;
-        private final int mWindowTouchSlop;
         private final AlertController mAlert;
         private final MyAdapter mAdapter;
 
-        private EnableAccessibilityController mEnableAccessibilityController;
-
-        private boolean mIntercepted;
-        private boolean mCancelOnUp;
-
         public GlobalActionsDialog(Context context, AlertParams params) {
             super(context, getDialogTheme(context));
             mContext = getContext();
             mAlert = AlertController.create(mContext, this, getWindow());
             mAdapter = (MyAdapter) params.mAdapter;
-            mWindowTouchSlop = ViewConfiguration.get(context).getScaledWindowTouchSlop();
             params.apply(mAlert);
         }
 
@@ -1221,76 +1210,10 @@
 
         @Override
         protected void onStart() {
-            // If global accessibility gesture can be performed, we will take care
-            // of dismissing the dialog on touch outside. This is because the dialog
-            // is dismissed on the first down while the global gesture is a long press
-            // with two fingers anywhere on the screen.
-            if (EnableAccessibilityController.canEnableAccessibilityViaGesture(mContext)) {
-                mEnableAccessibilityController = new EnableAccessibilityController(mContext,
-                        new Runnable() {
-                    @Override
-                    public void run() {
-                        dismiss();
-                    }
-                });
-                super.setCanceledOnTouchOutside(false);
-            } else {
-                mEnableAccessibilityController = null;
-                super.setCanceledOnTouchOutside(true);
-            }
-
+            super.setCanceledOnTouchOutside(true);
             super.onStart();
         }
 
-        @Override
-        protected void onStop() {
-            if (mEnableAccessibilityController != null) {
-                mEnableAccessibilityController.onDestroy();
-            }
-            super.onStop();
-        }
-
-        @Override
-        public boolean dispatchTouchEvent(MotionEvent event) {
-            if (mEnableAccessibilityController != null) {
-                final int action = event.getActionMasked();
-                if (action == MotionEvent.ACTION_DOWN) {
-                    View decor = getWindow().getDecorView();
-                    final int eventX = (int) event.getX();
-                    final int eventY = (int) event.getY();
-                    if (eventX < -mWindowTouchSlop
-                            || eventY < -mWindowTouchSlop
-                            || eventX >= decor.getWidth() + mWindowTouchSlop
-                            || eventY >= decor.getHeight() + mWindowTouchSlop) {
-                        mCancelOnUp = true;
-                    }
-                }
-                try {
-                    if (!mIntercepted) {
-                        mIntercepted = mEnableAccessibilityController.onInterceptTouchEvent(event);
-                        if (mIntercepted) {
-                            final long now = SystemClock.uptimeMillis();
-                            event = MotionEvent.obtain(now, now,
-                                    MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0);
-                            event.setSource(InputDevice.SOURCE_TOUCHSCREEN);
-                            mCancelOnUp = true;
-                        }
-                    } else {
-                        return mEnableAccessibilityController.onTouchEvent(event);
-                    }
-                } finally {
-                    if (action == MotionEvent.ACTION_UP) {
-                        if (mCancelOnUp) {
-                            cancel();
-                        }
-                        mCancelOnUp = false;
-                        mIntercepted = false;
-                    }
-                }
-            }
-            return super.dispatchTouchEvent(event);
-        }
-
         public ListView getListView() {
             return mAlert.getListView();
         }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 4b2b184..32b8c9b 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -149,8 +149,6 @@
 import android.media.AudioManager;
 import android.media.AudioSystem;
 import android.media.IAudioService;
-import android.media.Ringtone;
-import android.media.RingtoneManager;
 import android.media.session.MediaSessionLegacyHelper;
 import android.os.Binder;
 import android.os.Build;
@@ -441,6 +439,9 @@
     /** If true, hitting shift & menu will broadcast Intent.ACTION_BUG_REPORT */
     boolean mEnableShiftMenuBugReports = false;
 
+    /** Controller that supports enabling an AccessibilityService by holding down the volume keys */
+    private AccessibilityShortcutController mAccessibilityShortcutController;
+
     boolean mSafeMode;
     WindowState mStatusBar = null;
     int mStatusBarHeight;
@@ -748,7 +749,10 @@
     private boolean mScreenshotChordVolumeDownKeyTriggered;
     private long mScreenshotChordVolumeDownKeyTime;
     private boolean mScreenshotChordVolumeDownKeyConsumed;
-    private boolean mScreenshotChordVolumeUpKeyTriggered;
+    private boolean mA11yShortcutChordVolumeUpKeyTriggered;
+    private long mA11yShortcutChordVolumeUpKeyTime;
+    private boolean mA11yShortcutChordVolumeUpKeyConsumed;
+
     private boolean mScreenshotChordPowerKeyTriggered;
     private long mScreenshotChordPowerKeyTime;
 
@@ -794,6 +798,7 @@
     private static final int MSG_BACK_LONG_PRESS = 18;
     private static final int MSG_DISPOSE_INPUT_CONSUMER = 19;
     private static final int MSG_BACK_DELAYED_PRESS = 20;
+    private static final int MSG_ACCESSIBILITY_SHORTCUT = 21;
 
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_STATUS = 0;
     private static final int MSG_REQUEST_TRANSIENT_BARS_ARG_NAVIGATION = 1;
@@ -869,6 +874,9 @@
                     backMultiPressAction((Long) msg.obj, msg.arg1);
                     finishBackKeyPress();
                     break;
+                case MSG_ACCESSIBILITY_SHORTCUT:
+                    accessibilityShortcutActivated();
+                    break;
             }
         }
     }
@@ -1213,7 +1221,7 @@
         // If the power key has still not yet been handled, then detect short
         // press, long press, or multi press and decide what to do.
         mPowerKeyHandled = hungUp || mScreenshotChordVolumeDownKeyTriggered
-                || mScreenshotChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
+                || mA11yShortcutChordVolumeUpKeyTriggered || gesturedServiceIntercepted;
         if (!mPowerKeyHandled) {
             if (interactive) {
                 // When interactive, we're already awake.
@@ -1406,9 +1414,7 @@
             break;
         case LONG_PRESS_POWER_GLOBAL_ACTIONS:
             mPowerKeyHandled = true;
-            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
-                performAuditoryFeedbackForAccessibilityIfNeed();
-            }
+            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
             showGlobalActionsInternal();
             break;
         case LONG_PRESS_POWER_SHUT_OFF:
@@ -1439,6 +1445,10 @@
         }
     }
 
+    private void accessibilityShortcutActivated() {
+        mAccessibilityShortcutController.performAccessibilityShortcut();
+    }
+
     private void disposeInputConsumer(InputConsumer inputConsumer) {
         if (inputConsumer != null) {
             inputConsumer.dismiss();
@@ -1484,7 +1494,7 @@
     private void interceptScreenshotChord() {
         if (mScreenshotChordEnabled
                 && mScreenshotChordVolumeDownKeyTriggered && mScreenshotChordPowerKeyTriggered
-                && !mScreenshotChordVolumeUpKeyTriggered) {
+                && !mA11yShortcutChordVolumeUpKeyTriggered) {
             final long now = SystemClock.uptimeMillis();
             if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
                     && now <= mScreenshotChordPowerKeyTime
@@ -1497,6 +1507,22 @@
         }
     }
 
+    private void interceptAccessibilityShortcutChord() {
+        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable()
+                && mScreenshotChordVolumeDownKeyTriggered && mA11yShortcutChordVolumeUpKeyTriggered
+                && !mScreenshotChordPowerKeyTriggered) {
+            final long now = SystemClock.uptimeMillis();
+            if (now <= mScreenshotChordVolumeDownKeyTime + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS
+                    && now <= mA11yShortcutChordVolumeUpKeyTime
+                    + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS) {
+                mScreenshotChordVolumeDownKeyConsumed = true;
+                mA11yShortcutChordVolumeUpKeyConsumed = true;
+                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_ACCESSIBILITY_SHORTCUT),
+                        ViewConfiguration.get(mContext).getAccessibilityShortcutKeyTimeout());
+            }
+        }
+    }
+
     private long getScreenshotChordLongPressDelay() {
         if (mKeyguardDelegate.isShowing()) {
             // Double the time it takes to take a screenshot from the keyguard
@@ -1510,13 +1536,15 @@
         mHandler.removeCallbacks(mScreenshotRunnable);
     }
 
+    private void cancelPendingAccessibilityShortcutAction() {
+        mHandler.removeMessages(MSG_ACCESSIBILITY_SHORTCUT);
+    }
+
     private final Runnable mEndCallLongPress = new Runnable() {
         @Override
         public void run() {
             mEndCallKeyHandled = true;
-            if (!performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false)) {
-                performAuditoryFeedbackForAccessibilityIfNeed();
-            }
+            performHapticFeedbackLw(null, HapticFeedbackConstants.LONG_PRESS, false);
             showGlobalActionsInternal();
         }
     };
@@ -1698,7 +1726,8 @@
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
         mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
-
+        mAccessibilityShortcutController =
+                new AccessibilityShortcutController(mContext, new Handler());
         // Init display burn-in protection
         boolean burnInProtectionEnabled = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_enableBurnInProtection);
@@ -3251,6 +3280,33 @@
             }
         }
 
+        // If an accessibility shortcut might be partially complete, hold off dispatching until we
+        // know if it is complete or not
+        if (mAccessibilityShortcutController.isAccessibilityShortcutAvailable()
+                && (flags & KeyEvent.FLAG_FALLBACK) == 0) {
+            if (mScreenshotChordVolumeDownKeyTriggered ^ mA11yShortcutChordVolumeUpKeyTriggered) {
+                final long now = SystemClock.uptimeMillis();
+                final long timeoutTime = (mScreenshotChordVolumeDownKeyTriggered
+                        ? mScreenshotChordVolumeDownKeyTime : mA11yShortcutChordVolumeUpKeyTime)
+                        + SCREENSHOT_CHORD_DEBOUNCE_DELAY_MILLIS;
+                if (now < timeoutTime) {
+                    return timeoutTime - now;
+                }
+            }
+            if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN && mScreenshotChordVolumeDownKeyConsumed) {
+                if (!down) {
+                    mScreenshotChordVolumeDownKeyConsumed = false;
+                }
+                return -1;
+            }
+            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP && mA11yShortcutChordVolumeUpKeyConsumed) {
+                if (!down) {
+                    mA11yShortcutChordVolumeUpKeyConsumed = false;
+                }
+                return -1;
+            }
+        }
+
         // Cancel any pending meta actions if we see any other keys being pressed between the down
         // of the meta key and its corresponding up.
         if (mPendingMetaAction && !KeyEvent.isMetaKey(keyCode)) {
@@ -5760,22 +5816,32 @@
                             mScreenshotChordVolumeDownKeyConsumed = false;
                             cancelPendingPowerKeyAction();
                             interceptScreenshotChord();
+                            if (!keyguardActive) {
+                                interceptAccessibilityShortcutChord();
+                            }
                         }
                     } else {
                         mScreenshotChordVolumeDownKeyTriggered = false;
                         cancelPendingScreenshotChordAction();
+                        cancelPendingAccessibilityShortcutAction();
                     }
                 } else if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
                     if (down) {
-                        if (interactive && !mScreenshotChordVolumeUpKeyTriggered
+                        if (interactive && !mA11yShortcutChordVolumeUpKeyTriggered
                                 && (event.getFlags() & KeyEvent.FLAG_FALLBACK) == 0) {
-                            mScreenshotChordVolumeUpKeyTriggered = true;
+                            mA11yShortcutChordVolumeUpKeyTriggered = true;
+                            mA11yShortcutChordVolumeUpKeyTime = event.getDownTime();
+                            mA11yShortcutChordVolumeUpKeyConsumed = false;
                             cancelPendingPowerKeyAction();
                             cancelPendingScreenshotChordAction();
+                            if (!keyguardActive) {
+                                interceptAccessibilityShortcutChord();
+                            }
                         }
                     } else {
-                        mScreenshotChordVolumeUpKeyTriggered = false;
+                        mA11yShortcutChordVolumeUpKeyTriggered = false;
                         cancelPendingScreenshotChordAction();
+                        cancelPendingAccessibilityShortcutAction();
                     }
                 }
                 if (down) {
@@ -5863,6 +5929,8 @@
             }
 
             case KeyEvent.KEYCODE_POWER: {
+                // Any activity on the power button stops the accessibility shortcut
+                cancelPendingAccessibilityShortcutAction();
                 result &= ~ACTION_PASS_TO_USER;
                 isWakeKey = false; // wake-up will be handled separately
                 if (down) {
@@ -7416,31 +7484,11 @@
         }
     }
 
-    private void performAuditoryFeedbackForAccessibilityIfNeed() {
-        if (!isGlobalAccessibilityGestureEnabled()) {
-            return;
-        }
-        AudioManager audioManager = (AudioManager) mContext.getSystemService(
-                Context.AUDIO_SERVICE);
-        if (audioManager.isSilentMode()) {
-            return;
-        }
-        Ringtone ringTone = RingtoneManager.getRingtone(mContext,
-                Settings.System.DEFAULT_NOTIFICATION_URI);
-        ringTone.setStreamType(AudioManager.STREAM_MUSIC);
-        ringTone.play();
-    }
-
     private boolean isTheaterModeEnabled() {
         return Settings.Global.getInt(mContext.getContentResolver(),
                 Settings.Global.THEATER_MODE_ON, 0) == 1;
     }
 
-    private boolean isGlobalAccessibilityGestureEnabled() {
-        return Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.ENABLE_ACCESSIBILITY_GLOBAL_GESTURE_ENABLED, 0) == 1;
-    }
-
     private boolean areSystemNavigationKeysEnabled() {
         return Settings.Secure.getIntForUser(mContext.getContentResolver(),
                 Settings.Secure.SYSTEM_NAVIGATION_KEYS_ENABLED, 0, UserHandle.USER_CURRENT) == 1;
diff --git a/services/core/java/com/android/server/storage/AppFuseBridge.java b/services/core/java/com/android/server/storage/AppFuseBridge.java
index 23be9a3..5a1f473 100644
--- a/services/core/java/com/android/server/storage/AppFuseBridge.java
+++ b/services/core/java/com/android/server/storage/AppFuseBridge.java
@@ -16,79 +16,95 @@
 
 package com.android.server.storage;
 
-import android.annotation.CallSuper;
-import android.annotation.WorkerThread;
-import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.system.ErrnoException;
 import android.system.Os;
-import android.system.OsConstants;
-import android.util.Log;
-import com.android.internal.os.AppFuseMount;
+import com.android.internal.util.Preconditions;
 import libcore.io.IoUtils;
-
 import java.io.File;
-import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.BlockingQueue;
 
-public class AppFuseBridge implements Runnable {
-    private static final String TAG = AppFuseBridge.class.getSimpleName();
-
-    private final FileDescriptor mDeviceFd;
-    private final FileDescriptor mProxyFd;
-    private final CountDownLatch mMountLatch = new CountDownLatch(1);
+/**
+ * Runnable that delegates FUSE command from the kernel to application.
+ * run() blocks until all opened files on the FUSE mount point are closed. So this should be run in
+ * a separated thread.
+ */
+public class AppFuseBridge implements Runnable, AutoCloseable {
+    public static final String TAG = "AppFuseBridge";
 
     /**
-     * @param deviceFd FD of /dev/fuse. Ownership of fd is taken by AppFuseBridge.
-     * @param proxyFd FD of socket pair. Ownership of fd is taken by AppFuseBridge.
+     * The path AppFuse is mounted to.
+     * The first number is UID who is mounting the FUSE.
+     * THe second number is mount ID.
+     * The path must be sync with vold.
      */
-    private AppFuseBridge(FileDescriptor deviceFd, FileDescriptor proxyFd) {
-        mDeviceFd = deviceFd;
+    private static final String APPFUSE_MOUNT_NAME_TEMPLATE = "/mnt/appfuse/%d_%d";
+
+    private final IMountScope mMountScope;
+    private final ParcelFileDescriptor mProxyFd;
+    private final BlockingQueue<Boolean> mChannel;
+
+    /**
+     * @param mountScope Listener to unmount mount point.
+     * @param proxyFd FD of socket pair. Ownership of FD is taken by AppFuseBridge.
+     * @param channel Channel that the runnable send mount result to.
+     */
+    public AppFuseBridge(
+            IMountScope mountScope, ParcelFileDescriptor proxyFd, BlockingQueue<Boolean> channel) {
+        Preconditions.checkNotNull(mountScope);
+        Preconditions.checkNotNull(proxyFd);
+        Preconditions.checkNotNull(channel);
+        mMountScope = mountScope;
         mProxyFd = proxyFd;
-    }
-
-    public static AppFuseMount startMessageLoop(
-            int uid,
-            String name,
-            FileDescriptor deviceFd,
-            Handler handler,
-            ParcelFileDescriptor.OnCloseListener listener)
-                    throws IOException, ErrnoException, InterruptedException {
-        final FileDescriptor localFd = new FileDescriptor();
-        final FileDescriptor remoteFd = new FileDescriptor();
-        // Needs to specify OsConstants.SOCK_SEQPACKET to keep message boundaries.
-        Os.socketpair(OsConstants.AF_UNIX, OsConstants.SOCK_SEQPACKET, 0, remoteFd, localFd);
-
-        // Caller must invoke #start() after instantiate AppFuseBridge.
-        // Otherwise FDs will be leaked.
-        final AppFuseBridge bridge = new AppFuseBridge(deviceFd, localFd);
-        final Thread thread = new Thread(bridge, TAG);
-        thread.start();
-        try {
-            bridge.mMountLatch.await();
-        } catch (InterruptedException error) {
-            throw error;
-        }
-        return new AppFuseMount(
-                new File("/mnt/appfuse/" + uid + "_" + name),
-                ParcelFileDescriptor.fromFd(remoteFd, handler, listener));
+        mChannel = channel;
     }
 
     @Override
     public void run() {
-        // deviceFd and proxyFd must be closed in native_start_loop.
-        final int deviceFd = mDeviceFd.getInt$();
-        final int proxyFd = mProxyFd.getInt$();
-        mDeviceFd.setInt$(-1);
-        mProxyFd.setInt$(-1);
-        native_start_loop(deviceFd, proxyFd);
+        try {
+            // deviceFd and proxyFd must be closed in native_start_loop.
+            native_start_loop(
+                    mMountScope.getDeviceFileDescriptor().detachFd(),
+                    mProxyFd.detachFd());
+        } finally {
+            close();
+        }
+    }
+
+    public static ParcelFileDescriptor openFile(int uid, int mountId, int fileId, int mode)
+            throws FileNotFoundException {
+        final File mountPoint = getMountPoint(uid, mountId);
+        try {
+            if (Os.stat(mountPoint.getPath()).st_ino != 1) {
+                throw new FileNotFoundException("Could not find bridge mount point.");
+            }
+        } catch (ErrnoException e) {
+            throw new FileNotFoundException(
+                    "Failed to stat mount point: " + mountPoint.getParent());
+        }
+        return ParcelFileDescriptor.open(new File(mountPoint, String.valueOf(fileId)), mode);
+    }
+
+    private static File getMountPoint(int uid, int mountId) {
+        return new File(String.format(APPFUSE_MOUNT_NAME_TEMPLATE,  uid, mountId));
+    }
+
+    @Override
+    public void close() {
+        IoUtils.closeQuietly(mMountScope);
+        IoUtils.closeQuietly(mProxyFd);
+        // Invoke countDown here in case where close is invoked before mount.
+        mChannel.offer(false);
     }
 
     // Used by com_android_server_storage_AppFuse.cpp.
     private void onMount() {
-        mMountLatch.countDown();
+        mChannel.offer(true);
+    }
+
+    public static interface IMountScope extends AutoCloseable {
+        ParcelFileDescriptor getDeviceFileDescriptor();
     }
 
     private native boolean native_start_loop(int deviceFd, int proxyFd);
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 7ba95a4..02b46ec 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -271,21 +271,20 @@
     }
 
     @Override
-    public void setMultiProcessEnabledFromContext(Context context) {
-        boolean enableMultiProcess = false;
-        try {
-            enableMultiProcess = Settings.Global.getInt(context.getContentResolver(),
-                    Settings.Global.WEBVIEW_MULTIPROCESS) == 1;
-        } catch (Settings.SettingNotFoundException ex) {
-        }
-        WebViewZygote.setMultiprocessEnabled(enableMultiProcess);
+    public int getMultiProcessSetting(Context context) {
+        return Settings.Global.getInt(context.getContentResolver(),
+                                      Settings.Global.WEBVIEW_MULTIPROCESS, 0);
     }
 
     @Override
-    public void registerContentObserver(Context context, ContentObserver contentObserver) {
-        context.getContentResolver().registerContentObserver(
-                Settings.Global.getUriFor(Settings.Global.WEBVIEW_MULTIPROCESS),
-                false, contentObserver);
+    public void setMultiProcessSetting(Context context, int value) {
+        Settings.Global.putInt(context.getContentResolver(),
+                               Settings.Global.WEBVIEW_MULTIPROCESS, value);
+    }
+
+    @Override
+    public void notifyZygote(boolean enableMultiProcess) {
+        WebViewZygote.setMultiprocessEnabled(enableMultiProcess);
     }
 
     // flags declaring we want extra info from the package manager for webview providers
diff --git a/services/core/java/com/android/server/webkit/SystemInterface.java b/services/core/java/com/android/server/webkit/SystemInterface.java
index 2d7a998..fd137eb 100644
--- a/services/core/java/com/android/server/webkit/SystemInterface.java
+++ b/services/core/java/com/android/server/webkit/SystemInterface.java
@@ -50,6 +50,7 @@
     public PackageInfo getPackageInfoForProvider(WebViewProviderInfo configInfo)
             throws NameNotFoundException;
 
-    public void setMultiProcessEnabledFromContext(Context context);
-    public void registerContentObserver(Context context, ContentObserver contentObserver);
+    public int getMultiProcessSetting(Context context);
+    public void setMultiProcessSetting(Context context, int value);
+    public void notifyZygote(boolean enableMultiProcess);
 }
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index 0a7454f..311570e 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -261,6 +261,32 @@
             }
         }
 
+        @Override // Binder call
+        public boolean isMultiProcessEnabled() {
+            return WebViewUpdateService.this.mImpl.isMultiProcessEnabled();
+        }
+
+        @Override // Binder call
+        public void enableMultiProcess(boolean enable) {
+            if (getContext().checkCallingPermission(
+                        android.Manifest.permission.WRITE_SECURE_SETTINGS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                String msg = "Permission Denial: enableMultiProcess() from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid()
+                        + " requires " + android.Manifest.permission.WRITE_SECURE_SETTINGS;
+                Slog.w(TAG, msg);
+                throw new SecurityException(msg);
+            }
+
+            long callingId = Binder.clearCallingIdentity();
+            try {
+                WebViewUpdateService.this.mImpl.enableMultiProcess(enable);
+            } finally {
+                Binder.restoreCallingIdentity(callingId);
+            }
+        }
+
         @Override
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index 1a77c68..edfb11c 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -20,8 +20,6 @@
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.Signature;
-import android.database.ContentObserver;
-import android.net.Uri;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.util.Base64;
@@ -77,7 +75,6 @@
 
     private SystemInterface mSystemInterface;
     private WebViewUpdater mWebViewUpdater;
-    private SettingsObserver mSettingsObserver;
     final private Context mContext;
 
     public WebViewUpdateServiceImpl(Context context, SystemInterface systemInterface) {
@@ -97,10 +94,7 @@
     void prepareWebViewInSystemServer() {
         updateFallbackStateOnBoot();
         mWebViewUpdater.prepareWebViewInSystemServer();
-
-        // Register for changes in the multiprocess developer option. This has to be done
-        // here, since the update service gets created before the ContentResolver service.
-        mSettingsObserver = new SettingsObserver();
+        mSystemInterface.notifyZygote(isMultiProcessEnabled());
     }
 
     private boolean existsValidNonFallbackProvider(WebViewProviderInfo[] providers) {
@@ -247,6 +241,19 @@
                 && packageName.equals(fallbackProvider.packageName));
     }
 
+    boolean isMultiProcessEnabled() {
+        return mSystemInterface.getMultiProcessSetting(mContext) != 0;
+    }
+
+    void enableMultiProcess(boolean enable) {
+        PackageInfo current = getCurrentWebViewPackage();
+        mSystemInterface.setMultiProcessSetting(mContext, enable ? 1 : 0);
+        mSystemInterface.notifyZygote(enable);
+        if (current != null) {
+            mSystemInterface.killPackageDependents(current.packageName);
+        }
+    }
+
     /**
      * Class that decides what WebView implementation to use and prepares that implementation for
      * use.
@@ -740,31 +747,6 @@
     }
 
     /**
-     * Watches for changes in the WEBVIEW_MULTIPROCESS setting and lets
-     * the WebViewZygote know, so it can start or stop the zygote process
-     * appropriately.
-     */
-    private class SettingsObserver extends ContentObserver {
-        SettingsObserver() {
-            super(new Handler());
-
-            mSystemInterface.registerContentObserver(mContext, this);
-
-            // Push the current value of the setting immediately.
-            notifyZygote();
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            notifyZygote();
-        }
-
-        private void notifyZygote() {
-            mSystemInterface.setMultiProcessEnabledFromContext(mContext);
-        }
-    }
-
-    /**
      * Dump the state of this Service.
      */
     void dumpState(PrintWriter pw) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 10d1d8b..ac9859d 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -445,6 +445,7 @@
 
         mService.mOpeningApps.remove(this);
         mService.mUnknownAppVisibilityController.appRemoved(this);
+        mService.mTaskSnapshotController.onAppRemoved(this);
         waitingToShow = false;
         if (mService.mClosingApps.contains(this)) {
             delayed = true;
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 47003fa..592eaec 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1437,6 +1437,12 @@
         return "Display " + mDisplayId + " name=\"" + mDisplayInfo.name + "\"";
     }
 
+    /** Checks if stack with provided id is visible on this display. */
+    boolean isStackVisible(int stackId) {
+        final TaskStack stack = getStackById(stackId);
+        return (stack != null && stack.isVisible());
+    }
+
     /**
      * @return The docked stack, but only if it is visible, and {@code null} otherwise.
      */
@@ -2565,9 +2571,7 @@
                     : requestedPosition >= topChildPosition;
             int targetPosition = requestedPosition;
 
-            if (toTop
-                    && mService.isStackVisibleLocked(PINNED_STACK_ID)
-                    && stack.mStackId != PINNED_STACK_ID) {
+            if (toTop && isStackVisible(PINNED_STACK_ID) && stack.mStackId != PINNED_STACK_ID) {
                 // The pinned stack is always the top most stack (always-on-top) when it is visible.
                 TaskStack topStack = mChildren.get(topChildPosition);
                 if (topStack.mStackId != PINNED_STACK_ID) {
@@ -2577,8 +2581,8 @@
                 // So, stack is moved just below the pinned stack.
                 // When we're adding a new stack the target is the current pinned stack position.
                 // When we're positioning an existing stack the target is the position below pinned
-                // stack, because WindowContainer#positionAt() first removes element and then adds it
-                // to specified place.
+                // stack, because WindowContainer#positionAt() first removes element and then adds
+                // it to specified place.
                 targetPosition = adding ? topChildPosition : topChildPosition - 1;
             }
 
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 6ac172b..0cc6c70 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -228,7 +228,7 @@
             mService.configureDisplayPolicyLocked(dc);
 
             // TODO(multi-display): Create an input channel for each display with touch capability.
-            if (displayId == DEFAULT_DISPLAY) {
+            if (displayId == DEFAULT_DISPLAY && mService.canDispatchPointerEvents()) {
                 dc.mTapDetector = new TaskTapPointerEventListener(
                         mService, dc);
                 mService.registerPointerEventListener(dc.mTapDetector);
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index b1b7542..824d460 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -38,6 +38,7 @@
 import android.view.DisplayInfo;
 import android.view.Surface;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.EventLogTags;
 
 import java.io.PrintWriter;
@@ -104,32 +105,40 @@
     }
 
     DisplayContent getDisplayContent() {
-        return mStack.getDisplayContent();
+        return mStack != null ? mStack.getDisplayContent() : null;
+    }
+
+    int getAdjustedAddPosition(int suggestedPosition) {
+        final int size = mChildren.size();
+        if (suggestedPosition >= size) {
+            return Math.min(size, suggestedPosition);
+        }
+
+        for (int pos = 0; pos < size && pos < suggestedPosition; ++pos) {
+            // TODO: Confirm that this is the behavior we want long term.
+            if (mChildren.get(pos).removed) {
+                // suggestedPosition assumes removed tokens are actually gone.
+                ++suggestedPosition;
+            }
+        }
+        return Math.min(size, suggestedPosition);
     }
 
     @Override
-    void addChild(AppWindowToken wtoken, int addPos) {
-        final int lastPos = mChildren.size();
-        if (addPos >= lastPos) {
-            addPos = lastPos;
-        } else {
-            for (int pos = 0; pos < lastPos && pos < addPos; ++pos) {
-                if (mChildren.get(pos).removed) {
-                    // addPos assumes removed tokens are actually gone.
-                    ++addPos;
-                }
-            }
-        }
-
-        final WindowContainer parent = wtoken.getParent();
-        if (parent != null) {
-            parent.removeChild(wtoken);
-        }
-        super.addChild(wtoken, addPos);
+    void addChild(AppWindowToken wtoken, int position) {
+        position = getAdjustedAddPosition(position);
+        super.addChild(wtoken, position);
         wtoken.mTask = this;
         mDeferRemoval = false;
     }
 
+    @Override
+    void positionChildAt(int position, AppWindowToken child, boolean includingParents) {
+        position = getAdjustedAddPosition(position);
+        super.positionChildAt(position, child, includingParents);
+        mDeferRemoval = false;
+    }
+
     private boolean hasWindowsAlive() {
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             if (mChildren.get(i).hasWindowsAlive()) {
@@ -139,9 +148,14 @@
         return false;
     }
 
+    @VisibleForTesting
+    boolean shouldDeferRemoval() {
+        return hasWindowsAlive() && mStack.isAnimating();
+    }
+
     @Override
     void removeIfPossible() {
-        if (hasWindowsAlive() && mStack.isAnimating()) {
+        if (shouldDeferRemoval()) {
             if (DEBUG_STACK) Slog.i(TAG, "removeTask: deferring removing taskId=" + mTaskId);
             mDeferRemoval = true;
             return;
@@ -166,35 +180,29 @@
 
     void reparent(TaskStack stack, int position) {
         if (stack == mStack) {
-            return;
+            throw new IllegalArgumentException(
+                    "task=" + this + " already child of stack=" + mStack);
         }
         if (DEBUG_STACK) Slog.i(TAG, "reParentTask: removing taskId=" + mTaskId
                 + " from stack=" + mStack);
         EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "reParentTask");
+        final DisplayContent prevDisplayContent = getDisplayContent();
+
         getParent().removeChild(this);
         stack.addTask(this, position, showForAllUsers(), false /* moveParents */);
+
+        // Relayout display(s).
+        final DisplayContent displayContent = stack.getDisplayContent();
+        displayContent.setLayoutNeeded();
+        if (prevDisplayContent != displayContent) {
+            onDisplayChanged(displayContent);
+            prevDisplayContent.setLayoutNeeded();
+        }
     }
 
     /** @see com.android.server.am.ActivityManagerService#positionTaskInStack(int, int, int). */
-    void positionTaskInStack(TaskStack stack, int position, Rect bounds,
-            Configuration overrideConfig) {
-        if (mStack == null) {
-            // There is an assumption that task already has a stack at this point, so lets make
-            // sure we comply with it.
-            throw new IllegalStateException("Trying to position task that has no parent.");
-        }
-        if (stack != mStack) {
-            // Task is already attached to a different stack. First we need to remove it from there
-            // and add to top of the target stack. We will move it proper position afterwards.
-            if (DEBUG_STACK) Slog.i(TAG, "positionTaskInStack: removing taskId=" + mTaskId
-                    + " from stack=" + mStack);
-            EventLog.writeEvent(WM_TASK_REMOVED, mTaskId, "positionTaskInStack");
-            mStack.removeChild(this);
-            stack.addTask(this, position);
-        } else {
-            stack.positionChildAt(position, this, true /* includingParents */);
-        }
-
+    void positionAt(int position, Rect bounds, Configuration overrideConfig) {
+        mStack.positionChildAt(position, this, false /* includingParents */);
         resizeLocked(bounds, overrideConfig, false /* force */);
 
         for (int activityNdx = mChildren.size() - 1; activityNdx >= 0; --activityNdx) {
@@ -640,6 +648,11 @@
     }
 
     @Override
+    TaskWindowContainerController getController() {
+        return (TaskWindowContainerController) super.getController();
+    }
+
+    @Override
     public String toString() {
         return "{taskId=" + mTaskId + " appTokens=" + mChildren + " mdr=" + mDeferRemoval + "}";
     }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotCache.java b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
index 994a155..c86229b 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotCache.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotCache.java
@@ -20,6 +20,8 @@
 import android.app.ActivityManager.TaskSnapshot;
 import android.util.ArrayMap;
 
+import java.io.PrintWriter;
+
 /**
  * Caches snapshots. See {@link TaskSnapshotController}.
  * <p>
@@ -27,13 +29,65 @@
  */
 class TaskSnapshotCache {
 
-    private final ArrayMap<Task, TaskSnapshot> mCache = new ArrayMap<>();
+    private final ArrayMap<AppWindowToken, Task> mAppTaskMap = new ArrayMap<>();
+    private final ArrayMap<Task, CacheEntry> mCache = new ArrayMap<>();
 
     void putSnapshot(Task task, TaskSnapshot snapshot) {
-        mCache.put(task, snapshot);
+        final CacheEntry entry = mCache.get(task);
+        if (entry != null) {
+            mAppTaskMap.remove(entry.topApp);
+        }
+        final AppWindowToken top = task.getTopChild();
+        mAppTaskMap.put(top, task);
+        mCache.put(task, new CacheEntry(snapshot, task.getTopChild()));
     }
 
     @Nullable TaskSnapshot getSnapshot(Task task) {
-        return mCache.get(task);
+        final CacheEntry entry = mCache.get(task);
+        return entry != null ? entry.snapshot : null;
+    }
+
+    /**
+     * Cleans the cache after an app window token's process died.
+     */
+    void cleanCache(AppWindowToken wtoken) {
+        final Task task = mAppTaskMap.get(wtoken);
+        if (task != null) {
+            removeEntry(task);
+        }
+    }
+
+    private void removeEntry(Task task) {
+        final CacheEntry entry = mCache.get(task);
+        if (entry != null) {
+            mAppTaskMap.remove(entry.topApp);
+            mCache.remove(task);
+        }
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        final String doublePrefix = prefix + "  ";
+        final String triplePrefix = doublePrefix + "  ";
+        pw.println(prefix + "SnapshotCache");
+        for (int i = mCache.size() - 1; i >= 0; i--) {
+            final CacheEntry entry = mCache.valueAt(i);
+            pw.println(doublePrefix + "Entry taskId=" + mCache.keyAt(i).mTaskId);
+            pw.println(triplePrefix + "topApp=" + entry.topApp);
+            pw.println(triplePrefix + "snapshot=" + entry.snapshot);
+        }
+    }
+
+    private static final class CacheEntry {
+
+        /** The snapshot. */
+        final TaskSnapshot snapshot;
+
+        /** The app token that was on top of the task when the snapshot was taken */
+        final AppWindowToken topApp;
+
+        CacheEntry(TaskSnapshot snapshot, AppWindowToken topApp) {
+            this.snapshot = snapshot;
+            this.topApp = topApp;
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index 68aceae..df8679d 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -17,23 +17,18 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.ENABLE_TASK_SNAPSHOTS;
-import static android.graphics.Bitmap.Config.ARGB_8888;
-import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
-import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER;
-import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_NEVER;
-import static android.graphics.PixelFormat.RGBA_8888;
 
 import android.annotation.Nullable;
 import android.app.ActivityManager.StackId;
 import android.app.ActivityManager.TaskSnapshot;
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
 import android.graphics.GraphicBuffer;
 import android.util.ArraySet;
 import android.view.WindowManagerPolicy.StartingSurface;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.io.PrintWriter;
+
 /**
  * When an app token becomes invisible, we take a snapshot (bitmap) of the corresponding task and
  * put it into our cache. Internally we use gralloc buffers to be able to draw them wherever we
@@ -74,6 +69,9 @@
             final TaskSnapshot snapshot = snapshotTask(task);
             if (snapshot != null) {
                 mCache.putSnapshot(task, snapshot);
+                if (task.getController() != null) {
+                    task.getController().reportSnapshotChanged(snapshot);
+                }
             }
         }
     }
@@ -92,7 +90,7 @@
     }
 
     private TaskSnapshot snapshotTask(Task task) {
-        final AppWindowToken top = (AppWindowToken) task.getTop();
+        final AppWindowToken top = task.getTopChild();
         if (top == null) {
             return null;
         }
@@ -125,4 +123,25 @@
     private boolean canSnapshotTask(Task task) {
         return !StackId.isHomeOrRecentsStack(task.mStack.mStackId);
     }
+
+    /**
+     * Called when an {@link AppWindowToken} has been removed.
+     */
+    void onAppRemoved(AppWindowToken wtoken) {
+        // TODO: Clean from both recents and running cache.
+        mCache.cleanCache(wtoken);
+    }
+
+    /**
+     * Called when the process of an {@link AppWindowToken} has died.
+     */
+    void onAppDied(AppWindowToken wtoken) {
+
+        // TODO: Only clean from running cache.
+        mCache.cleanCache(wtoken);
+    }
+
+    void dump(PrintWriter pw, String prefix) {
+        mCache.dump(pw, prefix);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index c3e3141..4a09423 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -35,7 +35,6 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Slog;
-import android.view.Display;
 import android.view.IWindowSession;
 import android.view.Surface;
 import android.view.View;
@@ -147,6 +146,7 @@
         if (reportNextDraw) {
             reportDrawn();
         }
+        mSurface.release();
     }
 
     private void reportDrawn() {
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerController.java b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
index 0e4d048..96b79a6 100644
--- a/services/core/java/com/android/server/wm/TaskWindowContainerController.java
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerController.java
@@ -18,10 +18,13 @@
 
 import android.app.ActivityManager.TaskSnapshot;
 import android.content.res.Configuration;
-import android.graphics.GraphicBuffer;
 import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.util.EventLog;
 import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
 
 import static com.android.server.EventLogTags.WM_TASK_CREATED;
 import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
@@ -37,14 +40,30 @@
  * Test class: {@link TaskWindowContainerControllerTests}
  */
 public class TaskWindowContainerController
-        extends WindowContainerController<Task, WindowContainerListener> {
+        extends WindowContainerController<Task, TaskWindowContainerListener> {
+
+    private static final int REPORT_SNAPSHOT_CHANGED = 0;
 
     private final int mTaskId;
 
-    public TaskWindowContainerController(int taskId, int stackId, int userId, Rect bounds,
-            Configuration overrideConfig, int resizeMode, boolean homeTask, boolean isOnTopLauncher,
-            boolean toTop, boolean showForAllUsers) {
-        super(null, WindowManagerService.getInstance());
+    private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case REPORT_SNAPSHOT_CHANGED:
+                    if (mListener != null) {
+                        mListener.onSnapshotChanged((TaskSnapshot) msg.obj);
+                    }
+                    break;
+            }
+        }
+    };
+
+    public TaskWindowContainerController(int taskId, TaskWindowContainerListener listener,
+            int stackId, int userId, Rect bounds, Configuration overrideConfig, int resizeMode,
+            boolean homeTask, boolean isOnTopLauncher, boolean toTop, boolean showForAllUsers) {
+        super(listener, WindowManagerService.getInstance());
         mTaskId = taskId;
 
         synchronized(mWindowMap) {
@@ -59,13 +78,21 @@
                         + stackId);
             }
             EventLog.writeEvent(WM_TASK_CREATED, taskId, stackId);
-            final Task task = new Task(taskId, stack, userId, mService, bounds, overrideConfig,
-                    isOnTopLauncher, resizeMode, homeTask, this);
+            final Task task = createTask(taskId, stack, userId, bounds, overrideConfig, resizeMode,
+                    homeTask, isOnTopLauncher);
             final int position = toTop ? POSITION_TOP : POSITION_BOTTOM;
             stack.addTask(task, position, showForAllUsers, true /* moveParents */);
         }
     }
 
+    @VisibleForTesting
+    Task createTask(int taskId, TaskStack stack, int userId, Rect bounds,
+            Configuration overrideConfig, int resizeMode, boolean homeTask,
+            boolean isOnTopLauncher) {
+        return new Task(taskId, stack, userId, mService, bounds, overrideConfig, isOnTopLauncher,
+                resizeMode, homeTask, this);
+    }
+
     @Override
     public void removeContainer() {
         synchronized(mWindowMap) {
@@ -78,7 +105,7 @@
         }
     }
 
-    public void positionChildAt(AppWindowContainerController childController, int index) {
+    public void positionChildAt(AppWindowContainerController childController, int position) {
         synchronized(mService.mWindowMap) {
             final AppWindowToken aToken = childController.mContainer;
             if (aToken == null) {
@@ -91,7 +118,7 @@
             if (task == null) {
                 throw new IllegalArgumentException("positionChildAt: invalid task=" + this);
             }
-            task.addChild(aToken, index);
+            task.positionChildAt(position, aToken, false /* includeParents */);
         }
     }
 
@@ -106,13 +133,9 @@
             }
             final TaskStack stack = mService.mStackIdToStack.get(stackId);
             if (stack == null) {
-                if (DEBUG_STACK) Slog.i(TAG_WM,
-                        "reparent: could not find stackId=" + stackId);
-                return;
+                throw new IllegalArgumentException("reparent: could not find stackId=" + stackId);
             }
             mContainer.reparent(stack, position);
-            final DisplayContent displayContent = stack.getDisplayContent();
-            displayContent.setLayoutNeeded();
             mService.mWindowPlacerLocked.performSurfacePlacement();
         }
     }
@@ -140,22 +163,22 @@
     }
 
     // TODO: Move to positionChildAt() in stack controller once we have a stack controller.
-    public void positionAt(int stackId, int index, Rect bounds, Configuration overrideConfig) {
+    public void positionAt(int position, Rect bounds, Configuration overrideConfig) {
         synchronized (mWindowMap) {
             if (DEBUG_STACK) Slog.i(TAG_WM, "positionChildAt: positioning taskId=" + mTaskId
-                    + " in stackId=" + stackId + " at " + index);
+                    + " at " + position);
             if (mContainer == null) {
                 if (DEBUG_STACK) Slog.i(TAG_WM,
-                        "positionTaskInStack: could not find taskId=" + mTaskId);
+                        "positionAt: could not find taskId=" + mTaskId);
                 return;
             }
-            final TaskStack stack = mService.mStackIdToStack.get(stackId);
+            final TaskStack stack = mContainer.mStack;
             if (stack == null) {
                 if (DEBUG_STACK) Slog.i(TAG_WM,
-                        "positionTaskInStack: could not find stackId=" + stackId);
+                        "positionAt: could not find stack for task=" + mContainer);
                 return;
             }
-            mContainer.positionTaskInStack(stack, index, bounds, overrideConfig);
+            mContainer.positionAt(position, bounds, overrideConfig);
             final DisplayContent displayContent = stack.getDisplayContent();
             displayContent.setLayoutNeeded();
             mService.mWindowPlacerLocked.performSurfacePlacement();
@@ -253,6 +276,10 @@
         }
     }
 
+    void reportSnapshotChanged(TaskSnapshot snapshot) {
+        mHandler.obtainMessage(REPORT_SNAPSHOT_CHANGED, snapshot).sendToTarget();
+    }
+
     @Override
     public String toString() {
         return "{TaskWindowContainerController taskId=" + mTaskId + "}";
diff --git a/services/core/java/com/android/server/wm/TaskWindowContainerListener.java b/services/core/java/com/android/server/wm/TaskWindowContainerListener.java
new file mode 100644
index 0000000..61b202d
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskWindowContainerListener.java
@@ -0,0 +1,30 @@
+/*
+ * 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.wm;
+
+import android.app.ActivityManager.TaskSnapshot;
+
+/**
+ * Interface used by the creator of the controller to listen to changes with the container.
+ */
+public interface TaskWindowContainerListener extends WindowContainerListener {
+
+    /**
+     * Called when the snapshot of this task has changed.
+     */
+    void onSnapshotChanged(TaskSnapshot snapshot);
+}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index fd7ea6d..5b96263 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -234,13 +234,20 @@
      */
     @CallSuper
     void positionChildAt(int position, E child, boolean includingParents) {
+
+        if (child.getParent() != this) {
+            throw new IllegalArgumentException("removeChild: container=" + child.getName()
+                    + " is not a child of container=" + getName()
+                    + " current parent=" + child.getParent());
+        }
+
         if ((position < 0 && position != POSITION_BOTTOM)
                 || (position > mChildren.size() && position != POSITION_TOP)) {
             throw new IllegalArgumentException("positionAt: invalid position=" + position
                     + ", children number=" + mChildren.size());
         }
 
-        if (position == mChildren.size() - 1) {
+        if (position >= mChildren.size() - 1) {
             position = POSITION_TOP;
         } else if (position == 0) {
             position = POSITION_BOTTOM;
@@ -451,9 +458,9 @@
         return false;
     }
 
-    /** Returns the top child container or this container if there are no children. */
-    WindowContainer getTop() {
-        return mChildren.isEmpty() ? this : mChildren.peekLast();
+    /** Returns the top child container. */
+    E getTopChild() {
+        return mChildren.peekLast();
     }
 
     /** Returns true if there is still a removal being deferred */
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7cc77de..dcc0c6f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -235,6 +235,8 @@
 import java.util.HashMap;
 import java.util.List;
 
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+import static android.Manifest.permission.READ_FRAME_BUFFER;
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
         implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
@@ -3404,6 +3406,11 @@
         mPointerEventDispatcher.unregisterInputEventListener(listener);
     }
 
+    /** Check if the service is set to dispatch pointer events. */
+    boolean canDispatchPointerEvents() {
+        return mPointerEventDispatcher != null;
+    }
+
     // Called by window manager policy. Not exposed externally.
     @Override
     public int getLidState() {
@@ -3854,7 +3861,7 @@
 
     @Override
     public Bitmap screenshotWallpaper() {
-        if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
+        if (!checkCallingPermission(READ_FRAME_BUFFER,
                 "screenshotWallpaper()")) {
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
@@ -3875,7 +3882,7 @@
      */
     @Override
     public boolean requestAssistScreenshot(final IAssistScreenshotReceiver receiver) {
-        if (!checkCallingPermission(Manifest.permission.READ_FRAME_BUFFER,
+        if (!checkCallingPermission(READ_FRAME_BUFFER,
                 "requestAssistScreenshot()")) {
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
@@ -4236,7 +4243,7 @@
                 mRoot.mOrientationChangeComplete = false;
                 w.mLastFreezeDuration = 0;
             }
-
+            w.mReportOrientationChanged = true;
         }, true /* traverseTopToBottom */);
 
         if (rotateSeamlessly) {
@@ -4980,7 +4987,7 @@
         int keyboardPresence = 0;
         int navigationPresence = 0;
         final InputDevice[] devices = mInputManager.getInputDevices();
-        final int len = devices.length;
+        final int len = devices != null ? devices.length : 0;
         for (int i = 0; i < len; i++) {
             InputDevice device = devices[i];
             if (!device.isVirtual()) {
@@ -7143,6 +7150,7 @@
 
         mInputMonitor.dump(pw, "  ");
         mUnknownAppVisibilityController.dump(pw, "  ");
+        mTaskSnapshotController.dump(pw, "  ");
 
         if (dumpAll) {
             pw.print("  mSystemDecorLayer="); pw.print(mSystemDecorLayer);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 608f056..10aebe6 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -431,6 +431,11 @@
     int mLastVisibleLayoutRotation = -1;
 
     /**
+     * Set when we need to report the orientation change to client to trigger a relayout.
+     */
+    boolean mReportOrientationChanged;
+
+    /**
      * How long we last kept the screen frozen.
      */
     int mLastFreezeDuration;
@@ -1095,7 +1100,8 @@
                 || mFrameSizeChanged
                 || configChanged
                 || dragResizingChanged
-                || !isResizedWhileNotDragResizingReported()) {
+                || !isResizedWhileNotDragResizingReported()
+                || mReportOrientationChanged) {
             if (DEBUG_RESIZE || DEBUG_ORIENTATION) {
                 Slog.v(TAG_WM, "Resize reasons for w=" + this + ": "
                         + " contentInsetsChanged=" + mContentInsetsChanged
@@ -1110,7 +1116,8 @@
                         + " configChanged=" + configChanged
                         + " dragResizingChanged=" + dragResizingChanged
                         + " resizedWhileNotDragResizingReported="
-                        + isResizedWhileNotDragResizingReported());
+                        + isResizedWhileNotDragResizingReported()
+                        + " reportOrientationChanged=" + mReportOrientationChanged);
             }
 
             // If it's a dead window left on screen, and the configuration changed, there is nothing
@@ -2297,6 +2304,9 @@
                     final WindowState win = mService.windowForClientLocked(mSession, mClient, false);
                     Slog.i(TAG, "WIN DEATH: " + win);
                     if (win != null) {
+                        if (win.mAppToken != null && win.mAppToken.findMainWindow() == win) {
+                            mService.mTaskSnapshotController.onAppDied(win.mAppToken);
+                        }
                         win.removeIfPossible(shouldKeepVisibleDeadAppWindow());
                         if (win.mAttrs.type == TYPE_DOCK_DIVIDER) {
                             // The owner of the docked divider died :( We reset the docked stack,
@@ -3006,6 +3016,7 @@
             final Rect stableInsets = mLastStableInsets;
             final Rect outsets = mLastOutsets;
             final boolean reportDraw = mWinAnimator.mDrawState == DRAW_PENDING;
+            final boolean reportOrientation = mReportOrientationChanged;
             if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
                     && mClient instanceof IWindow.Stub) {
                 // To prevent deadlock simulate one-way call if win.mClient is a local object.
@@ -3014,7 +3025,8 @@
                     public void run() {
                         try {
                             dispatchResized(frame, overscanInsets, contentInsets, visibleInsets,
-                                    stableInsets, outsets, reportDraw, newConfig);
+                                    stableInsets, outsets, reportDraw, newConfig,
+                                    reportOrientation);
                         } catch (RemoteException e) {
                             // Not a remote call, RemoteException won't be raised.
                         }
@@ -3022,7 +3034,7 @@
                 });
             } else {
                 dispatchResized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
-                        outsets, reportDraw, newConfig);
+                        outsets, reportDraw, newConfig, reportOrientation);
             }
 
             //TODO (multidisplay): Accessibility supported only for the default display.
@@ -3038,6 +3050,7 @@
             mFrameSizeChanged = false;
             mResizedWhileNotDragResizingReported = true;
             mWinAnimator.mSurfaceResized = false;
+            mReportOrientationChanged = false;
         } catch (RemoteException e) {
             mOrientationChanging = false;
             mLastFreezeDuration = (int)(SystemClock.elapsedRealtime()
@@ -3078,8 +3091,9 @@
 
     private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
             Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
-            Configuration newConfig) throws RemoteException {
-        final boolean forceRelayout = isDragResizeChanged() || mResizedWhileNotDragResizing;
+            Configuration newConfig, boolean reportOrientation) throws RemoteException {
+        final boolean forceRelayout = isDragResizeChanged() || mResizedWhileNotDragResizing
+                || reportOrientation;
 
         mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
                 reportDraw, newConfig, getBackdropFrame(frame),
@@ -3372,11 +3386,13 @@
                     pw.print(" mDestroying="); pw.print(mDestroying);
                     pw.print(" mRemoved="); pw.println(mRemoved);
         }
-        if (mOrientationChanging || mAppFreezing || mTurnOnScreen) {
+        if (mOrientationChanging || mAppFreezing || mTurnOnScreen
+                || mReportOrientationChanged) {
             pw.print(prefix); pw.print("mOrientationChanging=");
                     pw.print(mOrientationChanging);
                     pw.print(" mAppFreezing="); pw.print(mAppFreezing);
                     pw.print(" mTurnOnScreen="); pw.println(mTurnOnScreen);
+                    pw.print(" mReportOrientationChanged="); pw.println(mReportOrientationChanged);
         }
         if (mLastFreezeDuration != 0) {
             pw.print(prefix); pw.print("mLastFreezeDuration=");
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index 1f7bf4a0..e9c944d 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -36,7 +36,7 @@
 
 static jboolean halOpen(JNIEnv* /* env */, jobject /* obj */) {
     // TODO(b/31632518)
-    mHal = IConsumerIr::getService("consumerir");
+    mHal = IConsumerIr::getService();
     return mHal != nullptr;
 }
 
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 27efd05..6791da9 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1462,7 +1462,11 @@
     NativeInputManager* im = reinterpret_cast<NativeInputManager*>(ptr);
 
     PointerIcon pointerIcon;
-    android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon);
+    status_t result = android_view_PointerIcon_getLoadedIcon(env, iconObj, &pointerIcon);
+    if (result) {
+        jniThrowRuntimeException(env, "Failed to load custom pointer icon.");
+        return;
+    }
 
     SpriteIcon spriteIcon;
     pointerIcon.bitmap.copyTo(&spriteIcon.bitmap, kN32_SkColorType);
diff --git a/services/core/jni/com_android_server_location_ContextHubService.cpp b/services/core/jni/com_android_server_location_ContextHubService.cpp
index 9106441..517fce0 100644
--- a/services/core/jni/com_android_server_location_ContextHubService.cpp
+++ b/services/core/jni/com_android_server_location_ContextHubService.cpp
@@ -14,7 +14,6 @@
  * limitations under the License.
  */
 
-
 #undef LOG_NDEBUG
 #undef LOG_TAG
 #define LOG_NDEBUG 0
@@ -26,11 +25,13 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <sys/endian.h>
 
 #include <chrono>
 #include <mutex>
 #include <queue>
 #include <unordered_map>
+#include <utility>
 
 #include <android-base/macros.h>
 #include <android/hardware/contexthub/1.0/IContexthub.h>
@@ -39,20 +40,20 @@
 #include "core_jni_helpers.h"
 #include "JNIHelp.h"
 
-using IContexthub = android::hardware::contexthub::V1_0::IContexthub;
+using android::hardware::contexthub::V1_0::AsyncEventType;
+using android::hardware::contexthub::V1_0::ContextHub;
+using android::hardware::contexthub::V1_0::ContextHubMsg;
+using android::hardware::contexthub::V1_0::HubAppInfo;
+using android::hardware::contexthub::V1_0::IContexthub;
+using android::hardware::contexthub::V1_0::IContexthubCallback;
+using android::hardware::contexthub::V1_0::NanoAppBinary;
+using android::hardware::contexthub::V1_0::Result;
+using android::hardware::contexthub::V1_0::TransactionResult;
 
-using Result = android::hardware::contexthub::V1_0::Result;
-using ContextHubMsg = android::hardware::contexthub::V1_0::ContextHubMsg;
-using IContexthubCallback = android::hardware::contexthub::V1_0::IContexthubCallback;
-using AsyncEventType = android::hardware::contexthub::V1_0::AsyncEventType;
-using TransactionResult = android::hardware::contexthub::V1_0::TransactionResult;
-using ContextHub = android::hardware::contexthub::V1_0::ContextHub;
-using HubAppInfo = android::hardware::contexthub::V1_0::HubAppInfo;
-
-template<typename T>
-using Return = android::hardware::Return<T>;
+using android::hardware::Return;
 
 using std::chrono::steady_clock;
+
 // If a transaction takes longer than this, we'll allow it to be
 // canceled by a new transaction.  Note we do _not_ automatically
 // cancel a transaction after this much time.  We can have a
@@ -63,6 +64,22 @@
 
 namespace android {
 
+constexpr uint32_t kNanoAppBinaryHeaderVersion = 1;
+
+// Important: this header is explicitly defined as little endian byte order, and
+// therefore may not match host endianness
+struct NanoAppBinaryHeader {
+    uint32_t headerVersion;        // 0x1 for this version
+    uint32_t magic;                // "NANO" (see NANOAPP_MAGIC in context_hub.h)
+    uint64_t appId;                // App Id, contains vendor id
+    uint32_t appVersion;           // Version of the app
+    uint32_t flags;                // Signed, encrypted
+    uint64_t hwHubType;            // Which hub type is this compiled for
+    uint8_t targetChreApiMajorVersion; // Which CHRE API version this is compiled for
+    uint8_t targetChreApiMinorVersion;
+    uint8_t reserved[6];
+} __attribute__((packed));
+
 enum HubMessageType {
     CONTEXT_HUB_APPS_ENABLE  = 1, // Enables loaded nano-app(s)
     CONTEXT_HUB_APPS_DISABLE = 2, // Disables loaded nano-app(s)
@@ -361,11 +378,12 @@
 
 ContextHubServiceDb db;
 
-int getHubIdForHubHandle(int hubHandle) {
-    if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs) {
-      return -1;
+bool getHubIdForHubHandle(int hubHandle, uint32_t *hubId) {
+    if (hubHandle < 0 || hubHandle >= db.hubInfo.numHubs || hubId == nullptr) {
+        return false;
     } else {
-      return db.hubInfo.hubs[hubHandle].hubId;
+        *hubId = db.hubInfo.hubs[hubHandle].hubId;
+        return true;
     }
 }
 
@@ -380,17 +398,6 @@
     return db.appInstances[id].hubHandle;
 }
 
-int getHubIdForAppInstance(jint id) {
-    int hubHandle = getHubHandleForAppInstance(id);
-
-    if (hubHandle < 0) {
-        ALOGD("Cannot find hub instance for app instance %d", id);
-        return -1;
-    }
-
-    return db.hubInfo.hubs[hubHandle].hubId;
-}
-
 jint getAppInstanceForAppId(uint64_t app_id) {
     auto end = db.appInstances.end();
     for (auto current = db.appInstances.begin(); current != end; ++current) {
@@ -1001,6 +1008,45 @@
     return retArray;
 }
 
+Result sendLoadNanoAppRequest(uint32_t hubId,
+                              jbyte *data,
+                              size_t dataBufferLength) {
+    auto header = reinterpret_cast<const NanoAppBinaryHeader *>(data);
+    Result result;
+
+    if (dataBufferLength < sizeof(NanoAppBinaryHeader)) {
+        ALOGE("Got short NanoApp, length %zu", dataBufferLength);
+        result = Result::BAD_PARAMS;
+    } else if (header->headerVersion != htole32(kNanoAppBinaryHeaderVersion)) {
+        ALOGE("Got unexpected NanoApp header version %" PRIu32,
+              letoh32(header->headerVersion));
+        result = Result::BAD_PARAMS;
+    } else {
+        NanoAppBinary nanoapp;
+
+        // Data from the common nanoapp header goes into explicit fields
+        nanoapp.appId      = letoh64(header->appId);
+        nanoapp.appVersion = letoh32(header->appVersion);
+        nanoapp.flags      = letoh32(header->flags);
+        nanoapp.targetChreApiMajorVersion = header->targetChreApiMajorVersion;
+        nanoapp.targetChreApiMinorVersion = header->targetChreApiMinorVersion;
+
+        // Everything past the header goes in customBinary
+        auto dataBytes = reinterpret_cast<const uint8_t *>(data);
+        std::vector<uint8_t> customBinary(
+            dataBytes + sizeof(NanoAppBinaryHeader),
+            dataBytes + dataBufferLength);
+        nanoapp.customBinary = std::move(customBinary);
+
+        ALOGW("Calling Load NanoApp on hub %d", hubId);
+        result = db.hubInfo.contextHub->loadNanoApp(hubId,
+                                                    nanoapp,
+                                                    CONTEXT_HUB_LOAD_APP);
+    }
+
+    return result;
+}
+
 jint nativeSendMessage(JNIEnv *env,
                        jobject instance,
                        jintArray header_,
@@ -1012,19 +1058,18 @@
     jint retVal = -1; // Default to failure
 
     jint *header = env->GetIntArrayElements(header_, 0);
-    unsigned int numHeaderElements = env->GetArrayLength(header_);
+    size_t numHeaderElements = env->GetArrayLength(header_);
     jbyte *data = env->GetByteArrayElements(data_, 0);
-    int dataBufferLength = env->GetArrayLength(data_);
+    size_t dataBufferLength = env->GetArrayLength(data_);
 
     if (numHeaderElements < MSG_HEADER_SIZE) {
         ALOGW("Malformed header len");
         return -1;
     }
 
-    uint32_t appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
+    jint appInstanceHandle = header[HEADER_FIELD_APP_INSTANCE];
     uint32_t msgType = header[HEADER_FIELD_MSG_TYPE];
     int hubHandle = -1;
-    int hubId;
     uint64_t appId;
 
     if (msgType == CONTEXT_HUB_UNLOAD_APP) {
@@ -1042,7 +1087,8 @@
         hubHandle = header[HEADER_FIELD_HUB_HANDLE];
     }
 
-    if (hubHandle < 0) {
+    uint32_t hubId = -1;
+    if (!getHubIdForHubHandle(hubHandle, &hubId)) {
         ALOGD("Invalid hub Handle %d", hubHandle);
         return -1;
     }
@@ -1072,46 +1118,41 @@
     Result result;
 
     if (msgType == CONTEXT_HUB_UNLOAD_APP) {
-        hubId = getHubIdForHubHandle(hubHandle);
-        ALOGW("Calling UnLoad NanoApp for app %" PRIx64 " on hub %d",
+        ALOGW("Calling UnLoad NanoApp for app %" PRIx64 " on hub %" PRIu32,
               db.appInstances[appInstanceHandle].appInfo.appId,
               hubId);
         result = db.hubInfo.contextHub->unloadNanoApp(
                 hubId, db.appInstances[appInstanceHandle].appInfo.appId, CONTEXT_HUB_UNLOAD_APP);
     } else {
-        if (header[HEADER_FIELD_APP_INSTANCE] == OS_APP_ID) {
+        if (appInstanceHandle == OS_APP_ID) {
             if (msgType == CONTEXT_HUB_LOAD_APP) {
-                std::vector<uint8_t> dataVector(reinterpret_cast<uint8_t *>(data),
-                                                reinterpret_cast<uint8_t *>(data + dataBufferLength));
-                hubId = getHubIdForHubHandle(hubHandle);
-                ALOGW("Calling Load NanoApp on hub %d", hubId);
-                result = db.hubInfo.contextHub->loadNanoApp(hubId,
-                                                            dataVector,
-                                                            CONTEXT_HUB_LOAD_APP);
+                result = sendLoadNanoAppRequest(hubId, data, dataBufferLength);
             } else {
                 ALOGD("Dropping OS addresses message of type - %" PRIu32, msgType);
                 result = Result::BAD_PARAMS;
             }
         } else {
-
-            appId = getAppIdForAppInstance(header[HEADER_FIELD_APP_INSTANCE]);
-            hubId = getHubIdForAppInstance(header[HEADER_FIELD_APP_INSTANCE]);
-
-            if (appId != static_cast<uint64_t>(INVALID_APP_ID) && hubId >= 0) {
+            appId = getAppIdForAppInstance(appInstanceHandle);
+            if (appId == static_cast<uint64_t>(INVALID_APP_ID)) {
+                ALOGD("Cannot find application instance %d", appInstanceHandle);
+                result = Result::BAD_PARAMS;
+            } else if (hubHandle != getHubHandleForAppInstance(appInstanceHandle)) {
+                ALOGE("Given hubHandle (%d) doesn't match expected for app instance (%d)",
+                      hubHandle,
+                      getHubHandleForAppInstance(appInstanceHandle));
+                result = Result::BAD_PARAMS;
+            } else {
                 ContextHubMsg msg;
                 msg.appName = appId;
                 msg.msgType = msgType;
                 msg.msg.setToExternal((unsigned char *)data, dataBufferLength);
 
-                ALOGW("Sending msg of type %" PRIu32 " len %u to app %" PRIx64 " on hub %d",
+                ALOGW("Sending msg of type %" PRIu32 " len %zu to app %" PRIx64 " on hub %" PRIu32,
                        msgType,
                        dataBufferLength,
                        appId,
                        hubId);
                 result = db.hubInfo.contextHub->sendMessageToHub(hubId, msg);
-            } else {
-                ALOGD("Cannot find application instance %u", header[HEADER_FIELD_APP_INSTANCE]);
-                result = Result::BAD_PARAMS;
             }
         }
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 76bab4f..8835ab2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -192,6 +192,7 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
@@ -236,7 +237,7 @@
 
     private static final int REQUEST_EXPIRE_PASSWORD = 5571;
 
-    private static final long MS_PER_DAY = 86400 * 1000;
+    private static final long MS_PER_DAY = TimeUnit.DAYS.toMillis(1);
 
     private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms
 
@@ -331,7 +332,7 @@
      * Minimum timeout in milliseconds after which unlocking with weak auth times out,
      * i.e. the user has to use a strong authentication method like password, PIN or pattern.
      */
-    private static final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h
+    private static final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = TimeUnit.HOURS.toMillis(1);
 
     /**
      * Strings logged with {@link
@@ -1155,7 +1156,7 @@
                 } else if (TAG_KEEP_UNINSTALLED_PACKAGES.equals(tag)) {
                     keepUninstalledPackages = readPackageList(parser, tag);
                 } else if (TAG_USER_RESTRICTIONS.equals(tag)) {
-                    UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions());
+                    userRestrictions = UserRestrictionsUtils.readRestrictions(parser);
                 } else if (TAG_DEFAULT_ENABLED_USER_RESTRICTIONS.equals(tag)) {
                     readAttributeValues(
                             parser, TAG_RESTRICTION, defaultEnabledRestrictionsAlreadySet);
@@ -2664,14 +2665,14 @@
             // Ignore
         }
 
+        // Generate a list of admins from the admin map
+        policy.mAdminList.addAll(policy.mAdminMap.values());
+
         // Might need to upgrade the file by rewriting it
         if (needsRewrite) {
             saveSettingsLocked(userHandle);
         }
 
-        // Generate a list of admins from the admin map
-        policy.mAdminList.addAll(policy.mAdminMap.values());
-
         validatePasswordOwnerLocked(policy);
         updateMaximumTimeToLockLocked(userHandle);
         updateLockTaskPackagesLocked(policy.mLockTaskPackages, userHandle);
@@ -6782,6 +6783,18 @@
         enforceManageUsers();
     }
 
+    private void enforceProfileOwnerOrSystemUser(ComponentName admin) {
+        synchronized (this) {
+            if (getActiveAdminWithPolicyForUidLocked(admin,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, mInjector.binderGetCallingUid())
+                            != null) {
+                return;
+            }
+        }
+        Preconditions.checkState(isCallerWithSystemUid(),
+                "Only profile owner, device owner and system may call this method.");
+    }
+
     private void ensureCallerPackage(@Nullable String packageName) {
         if (packageName == null) {
             Preconditions.checkState(isCallerWithSystemUid(),
@@ -7764,7 +7777,7 @@
 
         final int userHandle = mInjector.userHandleGetCallingUserId();
         synchronized (this) {
-            ActiveAdmin activeAdmin =
+            final ActiveAdmin activeAdmin =
                     getActiveAdminForCallerLocked(who,
                             DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             final boolean isDeviceOwner = isDeviceOwner(who, userHandle);
@@ -7779,7 +7792,12 @@
             }
 
             // Save the restriction to ActiveAdmin.
-            activeAdmin.ensureUserRestrictions().putBoolean(key, enabledFromThisOwner);
+            final Bundle restrictions = activeAdmin.ensureUserRestrictions();
+            if (enabledFromThisOwner) {
+                restrictions.putBoolean(key, true);
+            } else {
+                restrictions.remove(key);
+            }
             saveUserRestrictionsLocked(userHandle);
         }
     }
@@ -7792,39 +7810,46 @@
 
     private void pushUserRestrictions(int userId) {
         synchronized (this) {
-            final Bundle global;
-            final Bundle local = new Bundle();
-            if (mOwners.isDeviceOwnerUserId(userId)) {
-                global = new Bundle();
+            final boolean isDeviceOwner = mOwners.isDeviceOwnerUserId(userId);
+            final Bundle userRestrictions;
+            // Whether device owner enforces camera restriction.
+            boolean disallowCameraGlobally = false;
 
+            if (isDeviceOwner) {
                 final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
                 if (deviceOwner == null) {
                     return; // Shouldn't happen.
                 }
-
-                UserRestrictionsUtils.sortToGlobalAndLocal(deviceOwner.userRestrictions,
-                        global, local);
+                userRestrictions = deviceOwner.userRestrictions;
                 // DO can disable camera globally.
-                if (deviceOwner.disableCamera) {
-                    global.putBoolean(UserManager.DISALLOW_CAMERA, true);
-                }
+                disallowCameraGlobally = deviceOwner.disableCamera;
             } else {
-                global = null;
+                final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
+                userRestrictions = profileOwner != null ? profileOwner.userRestrictions : null;
+            }
 
-                ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
-                if (profileOwner != null) {
-                    UserRestrictionsUtils.merge(local, profileOwner.userRestrictions);
-                }
-            }
-            // Also merge in *local* camera restriction.
-            if (getCameraDisabled(/* who= */ null,
-                    userId, /* mergeDeviceOwnerRestriction= */ false)) {
-                local.putBoolean(UserManager.DISALLOW_CAMERA, true);
-            }
-            mUserManagerInternal.setDevicePolicyUserRestrictions(userId, local, global);
+            // Whether any admin enforces camera restriction.
+            final int cameraRestrictionScope =
+                    getCameraRestrictionScopeLocked(userId, disallowCameraGlobally);
+
+            mUserManagerInternal.setDevicePolicyUserRestrictions(userId, userRestrictions,
+                    isDeviceOwner, cameraRestrictionScope);
         }
     }
 
+    /**
+     * Get the scope of camera restriction for a given user if any.
+     */
+    private int getCameraRestrictionScopeLocked(int userId, boolean disallowCameraGlobally) {
+        if (disallowCameraGlobally) {
+            return UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
+        } else if (getCameraDisabled(
+                /* who= */ null, userId, /* mergeDeviceOwnerRestriction= */ false)) {
+            return UserManagerInternal.CAMERA_DISABLED_LOCALLY;
+        }
+        return UserManagerInternal.CAMERA_NOT_DISABLED;
+    }
+
     @Override
     public Bundle getUserRestrictions(ComponentName who) {
         if (!mHasFeature) {
@@ -8923,8 +8948,8 @@
         PackageManager packageManager = mInjector.getPackageManager();
 
         UserHandle user = mInjector.binderGetCallingUserHandle();
+        enforceProfileOwnerOrSystemUser(admin);
         synchronized (this) {
-            getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             long ident = mInjector.binderClearCallingIdentity();
             try {
                 int granted = mIPackageManager.checkPermission(permission,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 08fb591..b6c518b 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -282,12 +282,6 @@
             EventLog.writeEvent(EventLogTags.BOOT_PROGRESS_SYSTEM_RUN, uptimeMillis);
             if (!mRuntimeRestart && !mFirstBoot) {
                 MetricsLogger.histogram(null, "boot_system_server_init", uptimeMillis);
-                // Also report when first stage of init has started
-                long initStartNs = SystemProperties.getLong("ro.boottime.init", -1);
-                if (initStartNs >= 0) {
-                    MetricsLogger.histogram(null, "boot_android_init",
-                            (int)(initStartNs / 1000000));
-                }
             }
 
             // In case the runtime switched since last boot (such as when
@@ -383,8 +377,13 @@
             Slog.i(TAG, "Enabled StrictMode for system server main thread.");
         }
         if (!mRuntimeRestart && !mFirstBoot) {
-            MetricsLogger.histogram(null, "boot_system_server_ready",
-                    (int) SystemClock.elapsedRealtime());
+            int uptimeMillis = (int) SystemClock.elapsedRealtime();
+            MetricsLogger.histogram(null, "boot_system_server_ready", uptimeMillis);
+            final int MAX_UPTIME_MILLIS = 60 * 1000;
+            if (uptimeMillis > MAX_UPTIME_MILLIS) {
+                Slog.wtf("SystemServerTiming",
+                        "SystemServer init took too long. uptimeMillis=" + uptimeMillis);
+            }
         }
 
         // Loop forever.
@@ -955,6 +954,21 @@
                 }
                 traceEnd();
 
+                // Wifi Service must be started first for wifi-related services.
+                traceBeginAndSlog("StartWifi");
+                mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
+                traceEnd();
+                traceBeginAndSlog("StartWifiScanning");
+                mSystemServiceManager.startService(
+                        "com.android.server.wifi.scanner.WifiScanningService");
+                traceEnd();
+
+                if (!disableRtt) {
+                    traceBeginAndSlog("StartWifiRtt");
+                    mSystemServiceManager.startService("com.android.server.wifi.RttService");
+                    traceEnd();
+                }
+
                 if (context.getPackageManager().hasSystemFeature(
                         PackageManager.FEATURE_WIFI_AWARE)) {
                     traceBeginAndSlog("StartWifiAware");
@@ -970,19 +984,6 @@
                     mSystemServiceManager.startService(WIFI_P2P_SERVICE_CLASS);
                     traceEnd();
                 }
-                traceBeginAndSlog("StartWifi");
-                mSystemServiceManager.startService(WIFI_SERVICE_CLASS);
-                traceEnd();
-                traceBeginAndSlog("StartWifiScanning");
-                mSystemServiceManager.startService(
-                            "com.android.server.wifi.scanner.WifiScanningService");
-                traceEnd();
-
-                if (!disableRtt) {
-                    traceBeginAndSlog("StartWifiRtt");
-                    mSystemServiceManager.startService("com.android.server.wifi.RttService");
-                    traceEnd();
-                }
 
                 if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET) ||
                     mPackageManager.hasSystemFeature(PackageManager.FEATURE_USB_HOST)) {
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 87018ec..abdf683 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -865,13 +865,7 @@
         for (RouteInfo route : netlinkLinkProperties.getRoutes()) {
             newLp.addRoute(route);
         }
-        for (InetAddress dns : netlinkLinkProperties.getDnsServers()) {
-            // Only add likely reachable DNS servers.
-            // TODO: investigate deleting this.
-            if (newLp.isReachable(dns)) {
-                newLp.addDnsServer(dns);
-            }
-        }
+        addAllReachableDnsServers(newLp, netlinkLinkProperties.getDnsServers());
 
         // [3] Add in data from DHCPv4, if available.
         //
@@ -881,13 +875,7 @@
             for (RouteInfo route : mDhcpResults.getRoutes(mInterfaceName)) {
                 newLp.addRoute(route);
             }
-            for (InetAddress dns : mDhcpResults.dnsServers) {
-                // Only add likely reachable DNS servers.
-                // TODO: investigate deleting this.
-                if (newLp.isReachable(dns)) {
-                    newLp.addDnsServer(dns);
-                }
-            }
+            addAllReachableDnsServers(newLp, mDhcpResults.dnsServers);
             newLp.setDomains(mDhcpResults.domains);
 
             if (mDhcpResults.mtu != 0) {
@@ -909,6 +897,18 @@
         return newLp;
     }
 
+    private static void addAllReachableDnsServers(
+            LinkProperties lp, Iterable<InetAddress> dnses) {
+        // TODO: Investigate deleting this reachability check.  We should be
+        // able to pass everything down to netd and let netd do evaluation
+        // and RFC6724-style sorting.
+        for (InetAddress dns : dnses) {
+            if (!dns.isAnyLocalAddress() && lp.isReachable(dns)) {
+                lp.addDnsServer(dns);
+            }
+        }
+    }
+
     // Returns false if we have lost provisioning, true otherwise.
     private boolean handleLinkPropertiesUpdate(boolean sendCallbacks) {
         final LinkProperties newLp = assembleLinkProperties();
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 1c92e45..6c7f146 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -18,6 +18,7 @@
         package="com.android.frameworks.servicestests">
 
     <uses-permission android:name="android.permission.READ_LOGS" />
+    <uses-permission android:name="android.permission.ACCOUNT_MANAGER" />
     <uses-permission android:name="android.permission.WRITE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
@@ -46,6 +47,7 @@
     <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+    <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
 
     <application>
         <uses-library android:name="android.test.runner" />
@@ -64,6 +66,24 @@
           </intent-filter>
         </service>
 
+        <service android:name="com.android.server.accounts.TestAccountType1AuthenticatorService"
+            android:exported="false">
+          <intent-filter>
+            <action android:name="android.accounts.AccountAuthenticator" />
+          </intent-filter>
+          <meta-data android:name="android.accounts.AccountAuthenticator"
+              android:resource="@xml/test_account_type1_authenticator" />
+        </service>
+
+        <service android:name="com.android.server.accounts.TestAccountType2AuthenticatorService"
+            android:exported="false">
+          <intent-filter>
+            <action android:name="android.accounts.AccountAuthenticator" />
+          </intent-filter>
+          <meta-data android:name="android.accounts.AccountAuthenticator"
+              android:resource="@xml/test_account_type2_authenticator" />
+        </service>
+
         <receiver android:name="com.android.server.devicepolicy.ApplicationRestrictionsTest$AdminReceiver"
                 android:permission="android.permission.BIND_DEVICE_ADMIN">
             <meta-data android:name="android.app.device_admin"
@@ -116,7 +136,9 @@
         <activity android:name="com.android.server.pm.BaseShortcutManagerTest$ShortcutActivity3" />
 
         <activity android:name="com.android.server.pm.ShortcutTestActivity"
-            android:enabled="true" android:exported="true" />
+                 android:enabled="true" android:exported="true" />
+
+        <activity android:name="com.android.server.accounts.AccountAuthenticatorDummyActivity" />
 
         <activity-alias android:name="a.ShortcutEnabled"
             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
@@ -137,6 +159,12 @@
             android:enabled="true" android:exported="true">
             <meta-data android:name="android.app.shortcuts" android:resource="@xml/shortcut_1"/>
         </activity-alias>
+        <activity-alias android:name="a.ShortcutConfigActivity"
+                        android:targetActivity="com.android.server.pm.ShortcutTestActivity">
+            <intent-filter>
+                <action android:name="android.intent.action.CREATE_SHORTCUT" />
+            </intent-filter>
+        </activity-alias>
 
         <activity-alias android:name="a.DisabledMain"
             android:targetActivity="com.android.server.pm.ShortcutTestActivity"
diff --git a/services/tests/servicestests/res/values/strings.xml b/services/tests/servicestests/res/values/strings.xml
index 2f9d06c..121c1de 100644
--- a/services/tests/servicestests/res/values/strings.xml
+++ b/services/tests/servicestests/res/values/strings.xml
@@ -21,4 +21,8 @@
     <string name="shortcut_title2"></string>
     <string name="shortcut_text2"></string>
     <string name="shortcut_disabled_message2"></string>
+    <string name="test_account_type1_authenticator_label">AccountManagerService Test Account Type1</string>
+    <string name="test_account_type2_authenticator_label">AccountManagerService Test Account Type2</string>
+    <string name="test_account_type1">com.android.server.accounts.account_manager_service_test.account.type1</string>
+    <string name="test_account_type2">com.android.server.accounts.account_manager_service_test.account.type2</string>
 </resources>
diff --git a/services/tests/servicestests/res/xml/test_account_type1_authenticator.xml b/services/tests/servicestests/res/xml/test_account_type1_authenticator.xml
new file mode 100644
index 0000000..0c531de
--- /dev/null
+++ b/services/tests/servicestests/res/xml/test_account_type1_authenticator.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="@string/test_account_type1"
+    android:icon="@drawable/icon1"
+    android:smallIcon="@drawable/icon1"
+    android:label="@string/test_account_type1_authenticator_label" />
diff --git a/services/tests/servicestests/res/xml/test_account_type2_authenticator.xml b/services/tests/servicestests/res/xml/test_account_type2_authenticator.xml
new file mode 100644
index 0000000..f88eeb9
--- /dev/null
+++ b/services/tests/servicestests/res/xml/test_account_type2_authenticator.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:accountType="@string/test_account_type2"
+    android:icon="@drawable/icon1"
+    android:smallIcon="@drawable/icon1"
+    android:label="@string/test_account_type2_authenticator_label" />
diff --git a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
index 1189dae..75d9c39 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkScoreServiceTest.java
@@ -24,6 +24,7 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertSame;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
@@ -60,21 +61,28 @@
 import android.net.RecommendationRequest;
 import android.net.RecommendationResult;
 import android.net.ScoredNetwork;
+import android.net.Uri;
 import android.net.WifiKey;
 import android.net.wifi.WifiConfiguration;
 import android.os.Binder;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
 import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.provider.Settings;
 import android.support.test.InstrumentationRegistry;
 import android.support.test.filters.MediumTest;
 import android.support.test.runner.AndroidJUnit4;
 
 import com.android.server.devicepolicy.MockUtils;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -89,6 +97,8 @@
 import java.io.PrintWriter;
 import java.io.StringWriter;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Tests for {@link NetworkScoreService}.
@@ -114,6 +124,9 @@
     private ContentResolver mContentResolver;
     private NetworkScoreService mNetworkScoreService;
     private RecommendationRequest mRecommendationRequest;
+    private RemoteCallback mRemoteCallback;
+    private OnResultListener mOnResultListener;
+    private HandlerThread mHandlerThread;
 
     @Before
     public void setUp() throws Exception {
@@ -123,12 +136,25 @@
         mContentResolver = InstrumentationRegistry.getContext().getContentResolver();
         when(mContext.getContentResolver()).thenReturn(mContentResolver);
         when(mContext.getResources()).thenReturn(mResources);
-        mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager);
+        mHandlerThread = new HandlerThread("NetworkScoreServiceTest");
+        mHandlerThread.start();
+        mNetworkScoreService = new NetworkScoreService(mContext, mNetworkScorerAppManager,
+                mHandlerThread.getLooper());
         WifiConfiguration configuration = new WifiConfiguration();
         configuration.SSID = "NetworkScoreServiceTest_SSID";
         configuration.BSSID = "NetworkScoreServiceTest_BSSID";
         mRecommendationRequest = new RecommendationRequest.Builder()
             .setCurrentRecommendedWifiConfig(configuration).build();
+        mOnResultListener = new OnResultListener();
+        mRemoteCallback = new RemoteCallback(mOnResultListener);
+        Settings.Global.putLong(mContentResolver,
+                Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, -1L);
+        mNetworkScoreService.refreshRecommendationRequestTimeoutMs();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        mHandlerThread.quitSafely();
     }
 
     @Test
@@ -262,6 +288,116 @@
     }
 
     @Test
+    public void testRequestRecommendationAsync_noPermission() throws Exception {
+        doThrow(new SecurityException()).when(mContext)
+                .enforceCallingOrSelfPermission(eq(permission.BROADCAST_NETWORK_PRIVILEGED),
+                        anyString());
+        try {
+            mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
+                    mRemoteCallback);
+            fail("BROADCAST_NETWORK_PRIVILEGED not enforced.");
+        } catch (SecurityException e) {
+            // expected
+        }
+    }
+
+    @Test
+    public void testRequestRecommendationAsync_providerNotConnected() throws Exception {
+        mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
+                mRemoteCallback);
+        boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
+        assertTrue(callbackRan);
+        verifyZeroInteractions(mRecommendationProvider);
+    }
+
+    @Test
+    public void testRequestRecommendationAsync_requestTimesOut() throws Exception {
+        injectProvider();
+        Settings.Global.putLong(mContentResolver,
+                Settings.Global.NETWORK_RECOMMENDATION_REQUEST_TIMEOUT_MS, 1L);
+        mNetworkScoreService.refreshRecommendationRequestTimeoutMs();
+        mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
+                mRemoteCallback);
+        boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
+        assertTrue(callbackRan);
+        verify(mRecommendationProvider).requestRecommendation(eq(mRecommendationRequest),
+                isA(IRemoteCallback.Stub.class), anyInt());
+
+        assertTrue(mOnResultListener.receivedBundle.containsKey(EXTRA_RECOMMENDATION_RESULT));
+        RecommendationResult result =
+                mOnResultListener.receivedBundle.getParcelable(EXTRA_RECOMMENDATION_RESULT);
+        assertTrue(result.hasRecommendation());
+        assertEquals(mRecommendationRequest.getCurrentSelectedConfig().SSID,
+                result.getWifiConfiguration().SSID);
+    }
+
+    @Test
+    public void testRequestRecommendationAsync_requestSucceeds() throws Exception {
+        injectProvider();
+        final Bundle bundle = new Bundle();
+        doAnswer(invocation -> {
+            invocation.getArgumentAt(1, IRemoteCallback.class).sendResult(bundle);
+            return null;
+        }).when(mRecommendationProvider)
+                .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class),
+                        anyInt());
+
+        mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
+                mRemoteCallback);
+        boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
+        assertTrue(callbackRan);
+        // If it's not the same instance then something else ran the callback.
+        assertSame(bundle, mOnResultListener.receivedBundle);
+    }
+
+    @Test
+    public void testRequestRecommendationAsync_requestThrowsRemoteException() throws Exception {
+        injectProvider();
+        doThrow(new RemoteException()).when(mRecommendationProvider)
+                .requestRecommendation(eq(mRecommendationRequest), isA(IRemoteCallback.class),
+                        anyInt());
+
+        mNetworkScoreService.requestRecommendationAsync(mRecommendationRequest,
+                mRemoteCallback);
+        boolean callbackRan = mOnResultListener.countDownLatch.await(3, TimeUnit.SECONDS);
+        assertTrue(callbackRan);
+    }
+
+    @Test
+    public void dispatchingContentObserver_nullUri() throws Exception {
+        NetworkScoreService.DispatchingContentObserver observer =
+                new NetworkScoreService.DispatchingContentObserver(mContext, null /*handler*/);
+
+        observer.onChange(false, null);
+        // nothing to assert or verify but since we passed in a null handler we'd see a NPE
+        // if it were interacted with.
+    }
+
+    @Test
+    public void dispatchingContentObserver_dispatchUri() throws Exception {
+        final CountDownHandler handler = new CountDownHandler(mHandlerThread.getLooper());
+        NetworkScoreService.DispatchingContentObserver observer =
+                new NetworkScoreService.DispatchingContentObserver(mContext, handler);
+        Uri uri = Uri.parse("content://settings/global/network_score_service_test");
+        int expectedWhat = 24;
+        observer.observe(uri, expectedWhat);
+
+        observer.onChange(false, uri);
+        final boolean msgHandled = handler.latch.await(3, TimeUnit.SECONDS);
+        assertTrue(msgHandled);
+        assertEquals(expectedWhat, handler.receivedWhat);
+    }
+
+    @Test
+    public void oneTimeCallback_multipleCallbacks() throws Exception {
+        NetworkScoreService.OneTimeCallback callback =
+                new NetworkScoreService.OneTimeCallback(mRemoteCallback);
+        callback.sendResult(null);
+        callback.sendResult(null);
+        assertEquals(1, mOnResultListener.resultCount);
+    }
+
+    @Test
     public void testUpdateScores_notActiveScorer() {
         bindToScorer(false /*callerIsScorer*/);
 
@@ -515,4 +651,32 @@
                 isA(UserHandle.class))).thenReturn(true);
         mNetworkScoreService.systemRunning();
     }
+
+    private static class OnResultListener implements RemoteCallback.OnResultListener {
+        private final CountDownLatch countDownLatch = new CountDownLatch(1);
+        private int resultCount;
+        private Bundle receivedBundle;
+
+        @Override
+        public void onResult(Bundle result) {
+            countDownLatch.countDown();
+            resultCount++;
+            receivedBundle = result;
+        }
+    }
+
+    private static class CountDownHandler extends Handler {
+        CountDownLatch latch = new CountDownLatch(1);
+        int receivedWhat;
+
+        CountDownHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            latch.countDown();
+            receivedWhat = msg.what;
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountAuthenticatorDummyActivity.java b/services/tests/servicestests/src/com/android/server/accounts/AccountAuthenticatorDummyActivity.java
new file mode 100644
index 0000000..8a14e1b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountAuthenticatorDummyActivity.java
@@ -0,0 +1,42 @@
+/*
+ * 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.accounts;
+
+import android.accounts.AccountAuthenticatorResponse;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * Activity used by {@link com.android.server.accounts.TestAccountAuthenticator} to test the
+ * behavior of {@link AccountManagerService} when authenticator returns intent.
+ */
+public class AccountAuthenticatorDummyActivity extends Activity {
+
+    @Override
+    protected void onCreate(Bundle icicle) {
+        super.onCreate(icicle);
+        Intent intent = getIntent();
+        AccountAuthenticatorResponse response =
+                intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK);
+        Intent result = intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT);
+        if (response != null) {
+            response.onResult(result.getExtras());
+        }
+        setResult(RESULT_OK, result);
+        finish();
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index c74cda6..ee49a00 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -17,30 +17,47 @@
 package com.android.server.accounts;
 
 import static android.database.sqlite.SQLiteDatabase.deleteDatabase;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.accounts.Account;
+import android.accounts.AccountManager;
 import android.accounts.AccountManagerInternal;
 import android.accounts.AuthenticatorDescription;
+import android.accounts.CantAddAccountActivity;
+import android.accounts.IAccountManagerResponse;
 import android.app.AppOpsManager;
+import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.app.INotificationManager;
 import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.RegisteredServicesCache.ServiceInfo;
 import android.content.pm.RegisteredServicesCacheListener;
+import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
+import android.content.pm.RegisteredServicesCache.ServiceInfo;
 import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
@@ -48,6 +65,14 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 
+import com.android.frameworks.servicestests.R;
+import com.android.server.LocalServices;
+
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -61,6 +86,19 @@
 public class AccountManagerServiceTest extends AndroidTestCase {
     private static final String TAG = AccountManagerServiceTest.class.getSimpleName();
 
+    @Mock private Context mMockContext;
+    @Mock private AppOpsManager mMockAppOpsManager;
+    @Mock private UserManager mMockUserManager;
+    @Mock private PackageManager mMockPackageManager;
+    @Mock private DevicePolicyManagerInternal mMockDevicePolicyManagerInternal;
+    @Mock private DevicePolicyManager mMockDevicePolicyManager;
+    @Mock private IAccountManagerResponse mMockAccountManagerResponse;
+    @Mock private IBinder mMockBinder;
+
+    @Captor private ArgumentCaptor<Intent> mIntentCaptor;
+    @Captor private ArgumentCaptor<Bundle> mBundleCaptor;
+
+    private static final int LATCH_TIMEOUT_MS = 500;
     private static final String PREN_DB = "pren.db";
     private static final String DE_DB = "de.db";
     private static final String CE_DB = "ce.db";
@@ -69,8 +107,27 @@
 
     @Override
     protected void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        when(mMockPackageManager.checkSignatures(anyInt(), anyInt()))
+                    .thenReturn(PackageManager.SIGNATURE_MATCH);
+        final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
+        when(mMockUserManager.getUserInfo(eq(ui.id))).thenReturn(ui);
+        when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+        when(mMockContext.getSystemService(Context.APP_OPS_SERVICE)).thenReturn(mMockAppOpsManager);
+        when(mMockContext.getSystemService(Context.USER_SERVICE)).thenReturn(mMockUserManager);
+        when(mMockContext.getSystemServiceName(AppOpsManager.class)).thenReturn(
+                Context.APP_OPS_SERVICE);
+        when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+        Bundle bundle = new Bundle();
+        when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+        when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+                mMockDevicePolicyManager);
+        when(mMockAccountManagerResponse.asBinder()).thenReturn(mMockBinder);
+
         Context realTestContext = getContext();
-        MyMockContext mockContext = new MyMockContext(realTestContext);
+        MyMockContext mockContext = new MyMockContext(realTestContext, mMockContext);
         setContext(mockContext);
         mTestInjector = new TestInjector(realTestContext, mockContext);
         mAms = new AccountManagerService(mTestInjector);
@@ -104,12 +161,12 @@
     @SmallTest
     public void testCheckAddAccount() throws Exception {
         unlockSystemUser();
-        Account a11 = new Account("account1", "type1");
-        Account a21 = new Account("account2", "type1");
-        Account a31 = new Account("account3", "type1");
-        Account a12 = new Account("account1", "type2");
-        Account a22 = new Account("account2", "type2");
-        Account a32 = new Account("account3", "type2");
+        Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a21 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a31 = new Account("account3", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
+        Account a22 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
+        Account a32 = new Account("account3", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
         mAms.addAccountExplicitly(a11, "p11", null);
         mAms.addAccountExplicitly(a12, "p12", null);
         mAms.addAccountExplicitly(a21, "p21", null);
@@ -127,7 +184,8 @@
         assertEquals(a22, accounts[4]);
         assertEquals(a32, accounts[5]);
 
-        accounts = mAms.getAccounts("type1", mContext.getOpPackageName());
+        accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+                mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(3, accounts.length);
         assertEquals(a11, accounts[0]);
@@ -136,7 +194,8 @@
 
         mAms.removeAccountInternal(a21);
 
-        accounts = mAms.getAccounts("type1", mContext.getOpPackageName());
+        accounts = mAms.getAccounts(AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+                mContext.getOpPackageName());
         Arrays.sort(accounts, new AccountSorter());
         assertEquals(2, accounts.length);
         assertEquals(a11, accounts[0]);
@@ -146,8 +205,8 @@
     @SmallTest
     public void testPasswords() throws Exception {
         unlockSystemUser();
-        Account a11 = new Account("account1", "type1");
-        Account a12 = new Account("account1", "type2");
+        Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
         mAms.addAccountExplicitly(a11, "p11", null);
         mAms.addAccountExplicitly(a12, "p12", null);
 
@@ -163,12 +222,12 @@
     @SmallTest
     public void testUserdata() throws Exception {
         unlockSystemUser();
-        Account a11 = new Account("account1", "type1");
+        Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
         Bundle u11 = new Bundle();
         u11.putString("a", "a_a11");
         u11.putString("b", "b_a11");
         u11.putString("c", "c_a11");
-        Account a12 = new Account("account1", "type2");
+        Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
         Bundle u12 = new Bundle();
         u12.putString("a", "a_a12");
         u12.putString("b", "b_a12");
@@ -197,8 +256,8 @@
     @SmallTest
     public void testAuthtokens() throws Exception {
         unlockSystemUser();
-        Account a11 = new Account("account1", "type1");
-        Account a12 = new Account("account1", "type2");
+        Account a11 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a12 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
         mAms.addAccountExplicitly(a11, "p11", null);
         mAms.addAccountExplicitly(a12, "p12", null);
 
@@ -232,8 +291,8 @@
     @SmallTest
     public void testRemovedAccountSync() throws Exception {
         unlockSystemUser();
-        Account a1 = new Account("account1", "type1");
-        Account a2 = new Account("account2", "type2");
+        Account a1 = new Account("account1", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Account a2 = new Account("account2", AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
         mAms.addAccountExplicitly(a1, "p1", null);
         mAms.addAccountExplicitly(a2, "p2", null);
 
@@ -292,6 +351,329 @@
                 new File(ceDatabaseName).exists());
     }
 
+    @SmallTest
+    public void testStartAddAccountSessionWithNullResponse() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.startAddAccountSession(
+                null, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1,
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                null); // optionsIn
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionWithNullAccountType() throws Exception {
+        unlockSystemUser();
+        try {
+            mAms.startAddAccountSession(
+                    mMockAccountManagerResponse, // response
+                    null, // accountType
+                    "authTokenType",
+                    null, // requiredFeatures
+                    true, // expectActivityLaunch
+                    null); // optionsIn
+            fail("IllegalArgumentException expected. But no exception was thrown.");
+        } catch (IllegalArgumentException e) {
+        } catch(Exception e){
+            fail(String.format("Expect IllegalArgumentException, but got %s.", e));
+        }
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserCannotModifyAccountNoDPM() throws Exception {
+        unlockSystemUser();
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+        when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+        mAms.startAddAccountSession(
+                mMockAccountManagerResponse, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                null); // optionsIn
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+        verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM));
+
+        // verify the intent for default CantAddAccountActivity is sent.
+        Intent intent = mIntentCaptor.getValue();
+        assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName());
+        assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0),
+                AccountManager.ERROR_CODE_USER_RESTRICTED);
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserCannotModifyAccountWithDPM() throws Exception {
+        unlockSystemUser();
+        Bundle bundle = new Bundle();
+        bundle.putBoolean(UserManager.DISALLOW_MODIFY_ACCOUNTS, true);
+        when(mMockUserManager.getUserRestrictions(any(UserHandle.class))).thenReturn(bundle);
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        LocalServices.addService(
+                DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
+        when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent(
+                anyInt(), anyString())).thenReturn(new Intent());
+        when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent(
+                anyInt(), anyBoolean())).thenReturn(new Intent());
+
+        mAms.startAddAccountSession(
+                mMockAccountManagerResponse, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                null); // optionsIn
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_USER_RESTRICTED), anyString());
+        verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.SYSTEM));
+        verify(mMockDevicePolicyManagerInternal).createUserRestrictionSupportIntent(
+                anyInt(), anyString());
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserCannotModifyAccountForTypeNoDPM() throws Exception {
+        unlockSystemUser();
+        when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+                .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+
+        mAms.startAddAccountSession(
+                mMockAccountManagerResponse, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                null); // optionsIn
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+        verify(mMockContext).startActivityAsUser(mIntentCaptor.capture(), eq(UserHandle.SYSTEM));
+
+        // verify the intent for default CantAddAccountActivity is sent.
+        Intent intent = mIntentCaptor.getValue();
+        assertEquals(intent.getComponent().getClassName(), CantAddAccountActivity.class.getName());
+        assertEquals(intent.getIntExtra(CantAddAccountActivity.EXTRA_ERROR_CODE, 0),
+                AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE);
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserCannotModifyAccountForTypeWithDPM() throws Exception {
+        unlockSystemUser();
+        when(mMockContext.getSystemService(Context.DEVICE_POLICY_SERVICE)).thenReturn(
+                mMockDevicePolicyManager);
+        when(mMockDevicePolicyManager.getAccountTypesWithManagementDisabledAsUser(anyInt()))
+                .thenReturn(new String[]{AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, "BBB"});
+
+        LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
+        LocalServices.addService(
+                DevicePolicyManagerInternal.class, mMockDevicePolicyManagerInternal);
+        when(mMockDevicePolicyManagerInternal.createUserRestrictionSupportIntent(
+                anyInt(), anyString())).thenReturn(new Intent());
+        when(mMockDevicePolicyManagerInternal.createShowAdminSupportIntent(
+                anyInt(), anyBoolean())).thenReturn(new Intent());
+
+        mAms.startAddAccountSession(
+                mMockAccountManagerResponse, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                null); // optionsIn
+
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_MANAGEMENT_DISABLED_FOR_ACCOUNT_TYPE), anyString());
+        verify(mMockContext).startActivityAsUser(any(Intent.class), eq(UserHandle.SYSTEM));
+        verify(mMockDevicePolicyManagerInternal).createShowAdminSupportIntent(
+                anyInt(), anyBoolean());
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserSuccessWithoutPasswordForwarding() throws Exception {
+        unlockSystemUser();
+        when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+                PackageManager.PERMISSION_DENIED);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                false, // expectActivityLaunch
+                options); // optionsIn
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(sessionBundle);
+        // Assert that session bundle is encrypted and hence data not visible.
+        assertNull(sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+        // Assert password is not returned
+        assertNull(result.getString(AccountManager.KEY_PASSWORD));
+        assertNull(result.getString(AccountManager.KEY_AUTHTOKEN, null));
+        assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN,
+                result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserSuccessWithPasswordForwarding() throws Exception {
+        unlockSystemUser();
+        when(mMockContext.checkCallingOrSelfPermission(anyString())).thenReturn(
+                PackageManager.PERMISSION_GRANTED);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS);
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                false, // expectActivityLaunch
+                options); // optionsIn
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+        assertNotNull(sessionBundle);
+        // Assert that session bundle is encrypted and hence data not visible.
+        assertNull(sessionBundle.getString(AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1));
+        // Assert password is returned
+        assertEquals(result.getString(AccountManager.KEY_PASSWORD),
+                AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD);
+        assertNull(result.getString(AccountManager.KEY_AUTHTOKEN));
+        assertEquals(AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN,
+                result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserReturnWithInvalidIntent() throws Exception {
+        unlockSystemUser();
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+        when(mMockPackageManager.resolveActivityAsUser(
+                any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+        when(mMockPackageManager.checkSignatures(
+                anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_NO_MATCH);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE);
+
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                options); // optionsIn
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+        verify(mMockAccountManagerResponse).onError(
+                eq(AccountManager.ERROR_CODE_REMOTE_EXCEPTION), anyString());
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserReturnWithValidIntent() throws Exception {
+        unlockSystemUser();
+        ResolveInfo resolveInfo = new ResolveInfo();
+        resolveInfo.activityInfo = new ActivityInfo();
+        resolveInfo.activityInfo.applicationInfo = new ApplicationInfo();
+        when(mMockPackageManager.resolveActivityAsUser(
+                any(Intent.class), anyInt(), anyInt())).thenReturn(resolveInfo);
+        when(mMockPackageManager.checkSignatures(
+                anyInt(), anyInt())).thenReturn(PackageManager.SIGNATURE_MATCH);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE);
+
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                true, // expectActivityLaunch
+                options); // optionsIn
+        waitForLatch(latch);
+
+        verify(mMockAccountManagerResponse).onResult(mBundleCaptor.capture());
+        Bundle result = mBundleCaptor.getValue();
+        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
+        assertNotNull(intent);
+        assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_RESULT));
+        assertNotNull(intent.getParcelableExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK));
+    }
+
+    @SmallTest
+    public void testStartAddAccountSessionUserError() throws Exception {
+        unlockSystemUser();
+        Bundle options = createOptionsWithAccountName(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_ERROR);
+        options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+        options.putString(AccountManager.KEY_ERROR_MESSAGE,
+                AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        Response response = new Response(latch, mMockAccountManagerResponse);
+        mAms.startAddAccountSession(
+                response, // response
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1, // accountType
+                "authTokenType",
+                null, // requiredFeatures
+                false, // expectActivityLaunch
+                options); // optionsIn
+
+        waitForLatch(latch);
+        verify(mMockAccountManagerResponse).onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
+                AccountManagerServiceTestFixtures.ERROR_MESSAGE);
+        verify(mMockAccountManagerResponse, never()).onResult(any(Bundle.class));
+    }
+
+    private void waitForLatch(CountDownLatch latch) {
+        try {
+            latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            fail("should not throw an InterruptedException");
+        }
+    }
+
+    private Bundle createOptionsWithAccountName(final String accountName) {
+        Bundle sessionBundle = new Bundle();
+        sessionBundle.putString(
+                AccountManagerServiceTestFixtures.SESSION_DATA_NAME_1,
+                AccountManagerServiceTestFixtures.SESSION_DATA_VALUE_1);
+        sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE,
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        Bundle options = new Bundle();
+        options.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME, accountName);
+        options.putBundle(AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE,
+                sessionBundle);
+        options.putString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_PASSWORD,
+                AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD);
+        return options;
+    }
+
     private int readNumberOfAccountsFromDbFile(Context context, String dbName) {
         SQLiteDatabase ceDb = context.openOrCreateDatabase(dbName, 0, null);
         try (Cursor cursor = ceDb.rawQuery("SELECT count(*) FROM accounts", null)) {
@@ -310,78 +692,34 @@
         return intent;
     }
 
-    static class MockAccountAuthenticatorCache implements IAccountAuthenticatorCache {
-        private ArrayList<ServiceInfo<AuthenticatorDescription>> mServices;
-
-        MockAccountAuthenticatorCache() {
-            mServices = new ArrayList<>();
-            AuthenticatorDescription d1 = new AuthenticatorDescription("type1", "p1", 0, 0, 0, 0);
-            AuthenticatorDescription d2 = new AuthenticatorDescription("type2", "p2", 0, 0, 0, 0);
-            mServices.add(new ServiceInfo<>(d1, null, null));
-            mServices.add(new ServiceInfo<>(d2, null, null));
-        }
-
-        @Override
-        public ServiceInfo<AuthenticatorDescription> getServiceInfo(
-                AuthenticatorDescription type, int userId) {
-            for (ServiceInfo<AuthenticatorDescription> service : mServices) {
-                if (service.type.equals(type)) {
-                    return service;
-                }
-            }
-            return null;
-        }
-
-        @Override
-        public Collection<ServiceInfo<AuthenticatorDescription>> getAllServices(int userId) {
-            return mServices;
-        }
-
-        @Override
-        public void dump(
-                final FileDescriptor fd, final PrintWriter fout, final String[] args, int userId) {
-        }
-
-        @Override
-        public void setListener(
-                final RegisteredServicesCacheListener<AuthenticatorDescription> listener,
-                final Handler handler) {
-        }
-
-        @Override
-        public void invalidateCache(int userId) {
-        }
-
-        @Override
-        public void updateServices(int userId) {
-        }
-    }
-
     static class MyMockContext extends MockContext {
         private Context mTestContext;
-        private AppOpsManager mAppOpsManager;
-        private UserManager mUserManager;
-        private PackageManager mPackageManager;
+        private Context mMockContext;
 
-        MyMockContext(Context testContext) {
+        MyMockContext(Context testContext, Context mockContext) {
             this.mTestContext = testContext;
-            this.mAppOpsManager = mock(AppOpsManager.class);
-            this.mUserManager = mock(UserManager.class);
-            this.mPackageManager = mock(PackageManager.class);
-            when(mPackageManager.checkSignatures(anyInt(), anyInt()))
-                    .thenReturn(PackageManager.SIGNATURE_MATCH);
-            final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
-            when(mUserManager.getUserInfo(eq(ui.id))).thenReturn(ui);
+            this.mMockContext = mockContext;
         }
 
         @Override
         public int checkCallingOrSelfPermission(final String permission) {
-            return PackageManager.PERMISSION_GRANTED;
+            return mMockContext.checkCallingOrSelfPermission(permission);
+        }
+
+        @Override
+        public boolean bindServiceAsUser(Intent service, ServiceConnection conn, int flags,
+                UserHandle user) {
+            return mTestContext.bindServiceAsUser(service, conn, flags, user);
+        }
+
+        @Override
+        public void unbindService(ServiceConnection conn) {
+            mTestContext.unbindService(conn);
         }
 
         @Override
         public PackageManager getPackageManager() {
-            return mPackageManager;
+            return mMockContext.getPackageManager();
         }
 
         @Override
@@ -391,54 +729,62 @@
 
         @Override
         public Object getSystemService(String name) {
-            if (Context.APP_OPS_SERVICE.equals(name)) {
-                return mAppOpsManager;
-            } else if( Context.USER_SERVICE.equals(name)) {
-                return mUserManager;
-            }
-            return null;
+            return mMockContext.getSystemService(name);
         }
 
         @Override
         public String getSystemServiceName(Class<?> serviceClass) {
-            if (AppOpsManager.class.equals(serviceClass)) {
-                return Context.APP_OPS_SERVICE;
-            }
-            return null;
+            return mMockContext.getSystemServiceName(serviceClass);
+        }
+
+        @Override
+        public void startActivityAsUser(Intent intent, UserHandle user) {
+            mMockContext.startActivityAsUser(intent, user);
         }
 
         @Override
         public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
-            return null;
+            return mMockContext.registerReceiver(receiver, filter);
         }
 
         @Override
         public Intent registerReceiverAsUser(BroadcastReceiver receiver, UserHandle user,
                 IntentFilter filter, String broadcastPermission, Handler scheduler) {
-            return null;
+            return mMockContext.registerReceiverAsUser(
+                    receiver, user, filter, broadcastPermission, scheduler);
         }
 
         @Override
         public SQLiteDatabase openOrCreateDatabase(String file, int mode,
                 SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
-            Log.i(TAG, "openOrCreateDatabase " + file + " mode " + mode);
             return mTestContext.openOrCreateDatabase(file, mode, factory,errorHandler);
         }
 
         @Override
         public void sendBroadcastAsUser(Intent intent, UserHandle user) {
-            Log.i(TAG, "sendBroadcastAsUser " + intent + " " + user);
+            mMockContext.sendBroadcastAsUser(intent, user);
         }
 
         @Override
         public String getOpPackageName() {
-            return null;
+            return mMockContext.getOpPackageName();
+        }
+    }
+
+    static class TestAccountAuthenticatorCache extends AccountAuthenticatorCache {
+        public TestAccountAuthenticatorCache(Context realContext) {
+            super(realContext);
+        }
+
+        @Override
+        protected File getUserSystemDirectory(int userId) {
+            return new File(mContext.getCacheDir(), "authenticator");
         }
     }
 
     static class TestInjector extends AccountManagerService.Injector {
         private Context mRealContext;
-        TestInjector(Context realContext, MyMockContext mockContext) {
+        TestInjector(Context realContext, Context mockContext) {
             super(mockContext);
             mRealContext = realContext;
         }
@@ -454,7 +800,7 @@
 
         @Override
         IAccountAuthenticatorCache getAccountAuthenticatorCache() {
-            return new MockAccountAuthenticatorCache();
+            return new TestAccountAuthenticatorCache(mRealContext);
         }
 
         @Override
@@ -477,4 +823,31 @@
             return mock(INotificationManager.class);
         }
     }
+
+    class Response extends IAccountManagerResponse.Stub {
+        private CountDownLatch mLatch;
+        private IAccountManagerResponse mMockResponse;
+        public Response(CountDownLatch latch, IAccountManagerResponse mockResponse) {
+            mLatch = latch;
+            mMockResponse = mockResponse;
+        }
+
+        @Override
+        public void onResult(Bundle bundle) {
+            try {
+                mMockResponse.onResult(bundle);
+            } catch (RemoteException e) {
+            }
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onError(int code, String message) {
+            try {
+                mMockResponse.onError(code, message);
+            } catch (RemoteException e) {
+            }
+            mLatch.countDown();
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
new file mode 100644
index 0000000..9a2c190
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTestFixtures.java
@@ -0,0 +1,70 @@
+/*
+ * 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.accounts;
+
+import android.accounts.Account;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Constants shared between test AccountAuthenticators and AccountManagerServiceTest.
+ */
+public final class AccountManagerServiceTestFixtures {
+    public static final String KEY_ACCOUNT_NAME = "account_manager_service_test:account_name_key";
+    public static final String KEY_ACCOUNT_SESSION_BUNDLE =
+            "account_manager_service_test:account_session_bundle_key";
+    public static final String KEY_ACCOUNT_STATUS_TOKEN =
+            "account_manager_service_test:account_status_token_key";
+    public static final String KEY_ACCOUNT_PASSWORD =
+            "account_manager_service_test:account_password_key";
+
+    public static final String ACCOUNT_NAME_SUCCESS = "success_on_return@fixture.com";
+    public static final String ACCOUNT_NAME_INTERVENE = "intervene@fixture.com";
+    public static final String ACCOUNT_NAME_ERROR = "error@fixture.com";
+
+    public static final String ACCOUNT_NAME =
+            "com.android.server.accounts.account_manager_service_test.account.name";
+    public static final String ACCOUNT_TYPE_1 =
+            "com.android.server.accounts.account_manager_service_test.account.type1";
+    public static final String ACCOUNT_TYPE_2 =
+            "com.android.server.accounts.account_manager_service_test.account.type2";
+    public static final String ACCOUNT_FAKE_TYPE =
+            "com.android.server.accounts.account_manager_service_test.account.type.fake";
+
+    public static final String ACCOUNT_STATUS_TOKEN =
+            "com.android.server.accounts.account_manager_service_test.account.status.token";
+
+    public static final String ACCOUNT_PASSWORD =
+            "com.android.server.accounts.account_manager_service_test.account.password";
+    public static final String KEY_RESULT = "account_manager_service_test:result";
+    public static final String KEY_CALLBACK = "account_manager_service_test:callback";
+
+    public static final Account ACCOUNT_SUCCESS =
+            new Account(ACCOUNT_NAME_SUCCESS, ACCOUNT_TYPE_1);
+    public static final Account ACCOUNT_INTERVENE =
+            new Account(ACCOUNT_NAME_INTERVENE, ACCOUNT_TYPE_1);
+    public static final Account ACCOUNT_ERROR =
+            new Account(ACCOUNT_NAME_ERROR, ACCOUNT_TYPE_1);
+
+    public static final String SESSION_DATA_NAME_1 = "session.data.name.1";
+    public static final String SESSION_DATA_VALUE_1 = "session.data.value.1";
+
+    public static final String ERROR_MESSAGE =
+        "com.android.server.accounts.account_manager_service_test.error.message";
+
+    private AccountManagerServiceTestFixtures() {}
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
index 97adbe6..38b3735 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
@@ -26,7 +26,7 @@
 class PreNTestDatabaseHelper extends SQLiteOpenHelper {
 
     public static final String TOKEN_STRING = "token-string-123";
-    public static final String ACCOUNT_TYPE = "type1";
+    public static final String ACCOUNT_TYPE = AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2;
     public static final String ACCOUNT_NAME = "account@" + ACCOUNT_TYPE;
     public static final String ACCOUNT_PASSWORD = "Password";
     public static final String TOKEN_TYPE = "SID";
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
new file mode 100644
index 0000000..0db11e0c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1Authenticator.java
@@ -0,0 +1,312 @@
+/*
+ * 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.accounts;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.frameworks.servicestests.R;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * This authenticator is to mock account authenticator to test AccountManagerService.
+ */
+public class TestAccountType1Authenticator extends AbstractAccountAuthenticator {
+    private final AtomicInteger mTokenCounter  = new AtomicInteger(0);
+
+    private final String mAccountType;
+    private final Context mContext;
+
+    public TestAccountType1Authenticator(Context context, String accountType) {
+        super(context);
+        mAccountType = accountType;
+        mContext = context;
+    }
+
+    @Override
+    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+        throw new UnsupportedOperationException(
+                "editProperties is not yet supported by the TestAccountAuthenticator");
+    }
+
+    @Override
+    public Bundle addAccount(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+        if (!mAccountType.equals(accountType)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        Bundle result = new Bundle();
+        result.putString(AccountManager.KEY_ACCOUNT_NAME, "test_account@test.com");
+        result.putString(AccountManager.KEY_ACCOUNT_TYPE, mAccountType);
+        return result;
+    }
+
+    @Override
+    public Bundle confirmCredentials(
+            AccountAuthenticatorResponse response,
+            Account account,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "confirmCredentials is not yet supported by the TestAccountAuthenticator");
+    }
+
+    @Override
+    public Bundle getAuthToken(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "getAuthToken is not yet supported by the TestAccountAuthenticator");
+    }
+
+    @Override
+    public String getAuthTokenLabel(String authTokenType) {
+        throw new UnsupportedOperationException(
+                "getAuthTokenLabel is not yet supported by the TestAccountAuthenticator");
+    }
+
+    @Override
+    public Bundle updateCredentials(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        if (!mAccountType.equals(account.type)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+        Bundle result = new Bundle();
+        result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+        result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+        return result;
+    }
+
+    @Override
+    public Bundle hasFeatures(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String[] features) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "hasFeatures is not yet supported by the TestAccountAuthenticator");
+    }
+
+    @Override
+    public Bundle startAddAccountSession(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+        if (!mAccountType.equals(accountType)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        String accountName = null;
+        Bundle sessionBundle = null;
+        String password = null;
+        if (options != null) {
+            accountName = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME);
+            sessionBundle = options.getBundle(
+                    AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+            password = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_PASSWORD);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+            result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+            result.putString(AccountManager.KEY_PASSWORD, password);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.equals(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+            eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD, password);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+                    sessionBundle);
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
+                    eventualActivityResultData);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            fillResultWithError(result, options);
+        }
+
+        return result;
+    }
+
+    @Override
+    public Bundle startUpdateCredentialsSession(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options)
+            throws NetworkErrorException {
+
+        if (!mAccountType.equals(account.type)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        String accountName = null;
+        Bundle sessionBundle = null;
+        if (options != null) {
+            accountName = options.getString(AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME);
+            sessionBundle = options.getBundle(
+            AccountManagerServiceTestFixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+            result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+            result.putString(AccountManager.KEY_PASSWORD, "doesn't matter");
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.equals(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+                    AccountManagerServiceTestFixtures.ACCOUNT_STATUS_TOKEN);
+            eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD,
+                    AccountManagerServiceTestFixtures.ACCOUNT_PASSWORD);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+                    sessionBundle);
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
+                    eventualActivityResultData);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            fillResultWithError(result, options);
+        }
+        return result;
+    }
+
+    @Override
+    public Bundle finishSession(AccountAuthenticatorResponse response,
+            String accountType,
+            Bundle sessionBundle) throws NetworkErrorException {
+
+        if (!mAccountType.equals(accountType)) {
+            throw new IllegalArgumentException("Request to the wrong authenticator!");
+        }
+
+        String accountName = null;
+        if (sessionBundle != null) {
+            accountName = sessionBundle.getString(
+            AccountManagerServiceTestFixtures.KEY_ACCOUNT_NAME);
+        }
+
+        Bundle result = new Bundle();
+        if (accountName.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putString(AccountManager.KEY_ACCOUNT_NAME,
+                    AccountManagerServiceTestFixtures.ACCOUNT_NAME);
+            result.putString(AccountManager.KEY_ACCOUNT_TYPE,
+                    AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+            result.putString(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+        } else if (accountName.equals(
+                AccountManagerServiceTestFixtures.ACCOUNT_NAME_INTERVENE)) {
+            // Specify data to be returned by the eventual activity.
+            Intent eventualActivityResultData = new Intent();
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME,
+                    AccountManagerServiceTestFixtures.ACCOUNT_NAME);
+            eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE,
+                    AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+            eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+                    Integer.toString(mTokenCounter.incrementAndGet()));
+
+            // Fill result with Intent.
+            Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_RESULT,
+                    eventualActivityResultData);
+            intent.putExtra(AccountManagerServiceTestFixtures.KEY_CALLBACK, response);
+
+            result.putParcelable(AccountManager.KEY_INTENT, intent);
+        } else {
+            // fill with error
+            fillResultWithError(result, sessionBundle);
+        }
+        return result;
+    }
+
+    @Override
+    public Bundle isCredentialsUpdateSuggested(
+            final AccountAuthenticatorResponse response,
+            Account account,
+            String statusToken) throws NetworkErrorException {
+
+        Bundle result = new Bundle();
+        if (account.name.equals(AccountManagerServiceTestFixtures.ACCOUNT_NAME_SUCCESS)) {
+            // fill bundle with a success result.
+            result.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, true);
+        } else {
+            // fill with error
+            fillResultWithError(
+                    result, AccountManager.ERROR_CODE_INVALID_RESPONSE, "Default Error Message");
+        }
+
+        response.onResult(result);
+        return null;
+    }
+
+    private void fillResultWithError(Bundle result, Bundle options) {
+        int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+        String errorMsg = "Default Error Message";
+        if (options != null) {
+            errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+            errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+        }
+        fillResultWithError(result, errorCode, errorMsg);
+    }
+
+    private void fillResultWithError(Bundle result, int errorCode, String errorMsg) {
+        result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+        result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1AuthenticatorService.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1AuthenticatorService.java
new file mode 100644
index 0000000..acd1046
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType1AuthenticatorService.java
@@ -0,0 +1,33 @@
+/*
+ * 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.accounts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * a test Mock Service for wrapping the TestAccountType1Authenticator
+ */
+public class TestAccountType1AuthenticatorService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        TestAccountType1Authenticator authenticator = new TestAccountType1Authenticator(
+                this, AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        return authenticator.getIBinder();
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2Authenticator.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2Authenticator.java
new file mode 100644
index 0000000..4cbc8cb
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2Authenticator.java
@@ -0,0 +1,147 @@
+/*
+ * 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.accounts;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import com.android.frameworks.servicestests.R;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * This authenticator is to mock account authenticator to test AccountManagerService.
+ */
+public class TestAccountType2Authenticator extends AbstractAccountAuthenticator {
+    private final AtomicInteger mTokenCounter  = new AtomicInteger(0);
+
+    private final String mAccountType;
+    private final Context mContext;
+
+    public TestAccountType2Authenticator(Context context, String accountType) {
+        super(context);
+        mAccountType = accountType;
+        mContext = context;
+    }
+
+    @Override
+    public Bundle editProperties(AccountAuthenticatorResponse response, String accountType) {
+        throw new UnsupportedOperationException(
+                "editProperties is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle addAccount(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "addAccount is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle confirmCredentials(
+            AccountAuthenticatorResponse response,
+            Account account,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "confirmCredentials is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle getAuthToken(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "getAuthToken is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public String getAuthTokenLabel(String authTokenType) {
+        throw new UnsupportedOperationException(
+                "getAuthTokenLabel is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle updateCredentials(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "updateCredentials is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle hasFeatures(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String[] features) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "hasFeatures is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle startAddAccountSession(
+            AccountAuthenticatorResponse response,
+            String accountType,
+            String authTokenType,
+            String[] requiredFeatures,
+            Bundle options) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "startAddAccountSession is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle startUpdateCredentialsSession(
+            AccountAuthenticatorResponse response,
+            Account account,
+            String authTokenType,
+            Bundle options)
+            throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "startUpdateCredentialsSession is not supported " +
+                "by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle finishSession(AccountAuthenticatorResponse response,
+            String accountType,
+            Bundle sessionBundle) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "finishSession is not supported by the TestAccountType2Authenticator");
+    }
+
+    @Override
+    public Bundle isCredentialsUpdateSuggested(
+            final AccountAuthenticatorResponse response,
+            Account account,
+            String statusToken) throws NetworkErrorException {
+        throw new UnsupportedOperationException(
+                "isCredentialsUpdateSuggested is not supported " +
+                "by the TestAccountType2Authenticator");
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2AuthenticatorService.java b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2AuthenticatorService.java
new file mode 100644
index 0000000..b80dc78
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/TestAccountType2AuthenticatorService.java
@@ -0,0 +1,33 @@
+/*
+ * 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.accounts;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * a test Mock Service for wrapping the TestAccountType2Authenticator
+ */
+public class TestAccountType2AuthenticatorService extends Service {
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        TestAccountType2Authenticator authenticator = new TestAccountType2Authenticator(
+                this, AccountManagerServiceTestFixtures.ACCOUNT_TYPE_2);
+        return authenticator.getIBinder();
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
index 4886a5f..677e468 100644
--- a/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appwidget/AppWidgetServiceImplTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -28,6 +29,7 @@
 import android.app.admin.DevicePolicyManagerInternal;
 import android.appwidget.AppWidgetManager;
 import android.appwidget.AppWidgetProviderInfo;
+import android.appwidget.PendingHostUpdate;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContextWrapper;
@@ -39,11 +41,17 @@
 import android.os.UserHandle;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
+import android.widget.RemoteViews;
 
+import com.android.internal.appwidget.IAppWidgetHost;
 import com.android.server.LocalServices;
 
 import org.mockito.ArgumentCaptor;
 
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+
 
 /**
  * Tests for {@link AppWidgetManager} and {@link AppWidgetServiceImpl}.
@@ -57,11 +65,15 @@
 @SmallTest
 public class AppWidgetServiceImplTest extends InstrumentationTestCase {
 
+    private static final int HOST_ID = 42;
+
     private TestContext mTestContext;
+    private String mPkgName;
     private AppWidgetServiceImpl mService;
     private AppWidgetManager mManager;
 
     private ShortcutServiceInternal mMockShortcutService;
+    private IAppWidgetHost mMockHost;
 
     @Override
     protected void setUp() throws Exception {
@@ -70,12 +82,13 @@
         LocalServices.removeServiceForTest(ShortcutServiceInternal.class);
 
         mTestContext = new TestContext();
+        mPkgName = mTestContext.getOpPackageName();
         mService = new AppWidgetServiceImpl(mTestContext);
         mManager = new AppWidgetManager(mTestContext, mService);
 
         mMockShortcutService = mock(ShortcutServiceInternal.class);
+        mMockHost = mock(IAppWidgetHost.class);
         LocalServices.addService(ShortcutServiceInternal.class, mMockShortcutService);
-
         mService.onStart();
     }
 
@@ -108,6 +121,142 @@
         assertEquals(provider, providerCaptor.getValue().provider);
     }
 
+    public void testProviderUpdatesReceived() throws Exception {
+        int widgetId = setupHostAndWidget();
+        RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1);
+        mManager.updateAppWidget(widgetId, view);
+        mManager.updateAppWidget(widgetId, view);
+        mManager.updateAppWidget(widgetId, view);
+        mManager.updateAppWidget(widgetId, view);
+
+        flushMainThread();
+        verify(mMockHost, times(4)).updateAppWidget(eq(widgetId), any(RemoteViews.class));
+
+        reset(mMockHost);
+        mManager.notifyAppWidgetViewDataChanged(widgetId, 22);
+        flushMainThread();
+        verify(mMockHost, times(1)).viewDataChanged(eq(widgetId), eq(22));
+    }
+
+    public void testProviderUpdatesNotReceived() throws Exception {
+        int widgetId = setupHostAndWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+        RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1);
+        mManager.updateAppWidget(widgetId, view);
+        mManager.notifyAppWidgetViewDataChanged(widgetId, 22);
+
+        flushMainThread();
+        verify(mMockHost, times(0)).updateAppWidget(anyInt(), any(RemoteViews.class));
+        verify(mMockHost, times(0)).viewDataChanged(anyInt(), eq(22));
+    }
+
+    public void testNoUpdatesReceived_queueEmpty() {
+        int widgetId = setupHostAndWidget();
+        RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1);
+        mManager.updateAppWidget(widgetId, view);
+        mManager.notifyAppWidgetViewDataChanged(widgetId, 22);
+        mService.stopListening(mPkgName, HOST_ID);
+
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[0]).getList();
+        assertTrue(updates.isEmpty());
+    }
+
+    /**
+     * Sends dummy widget updates to {@link #mManager}.
+     * @param widgetId widget to update
+     * @param viewIds a list of view ids for which
+     *                {@link AppWidgetManager#notifyAppWidgetViewDataChanged} will be called
+     */
+    private void sendDummyUpdates(int widgetId, int... viewIds) {
+        Random r = new Random();
+        RemoteViews view = new RemoteViews(mPkgName, android.R.layout.simple_list_item_1);
+        for (int i = r.nextInt(10) + 2; i >= 0; i--) {
+            mManager.updateAppWidget(widgetId, view);
+        }
+
+        for (int viewId : viewIds) {
+            mManager.notifyAppWidgetViewDataChanged(widgetId, viewId);
+            for (int i = r.nextInt(3); i >= 0; i--) {
+                mManager.updateAppWidget(widgetId, view);
+            }
+        }
+    }
+
+    public void testNoUpdatesReceived_queueNonEmpty_noWidgetId() {
+        int widgetId = setupHostAndWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+
+        sendDummyUpdates(widgetId, 22, 23);
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[0]).getList();
+        assertTrue(updates.isEmpty());
+    }
+
+    public void testUpdatesReceived_queueNotEmpty_widgetIdProvided() {
+        int widgetId = setupHostAndWidget();
+        int widgetId2 = bindNewWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+
+        sendDummyUpdates(widgetId, 22, 23);
+        sendDummyUpdates(widgetId2, 100, 101, 102);
+
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[]{widgetId}).getList();
+        // 3 updates corresponding to the first widget
+        assertEquals(3, updates.size());
+    }
+
+    public void testUpdatesReceived_queueNotEmpty_widgetIdProvided2() {
+        int widgetId = setupHostAndWidget();
+        int widgetId2 = bindNewWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+
+        sendDummyUpdates(widgetId, 22, 23);
+        sendDummyUpdates(widgetId2, 100, 101, 102);
+
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[]{widgetId2}).getList();
+        // 4 updates corresponding to the second widget
+        assertEquals(4, updates.size());
+    }
+
+    public void testUpdatesReceived_queueNotEmpty_multipleWidgetIdProvided() {
+        int widgetId = setupHostAndWidget();
+        int widgetId2 = bindNewWidget();
+        mService.stopListening(mPkgName, HOST_ID);
+
+        sendDummyUpdates(widgetId, 22, 23);
+        sendDummyUpdates(widgetId2, 100, 101, 102);
+
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[]{widgetId, widgetId2}).getList();
+        // 3 updates for first widget and 4 for second
+        assertEquals(7, updates.size());
+    }
+
+    private int setupHostAndWidget() {
+        List<PendingHostUpdate> updates = mService.startListening(
+                mMockHost, mPkgName, HOST_ID, new int[0]).getList();
+        assertTrue(updates.isEmpty());
+        return bindNewWidget();
+    }
+
+    private int bindNewWidget() {
+        ComponentName provider = new ComponentName(mTestContext, DummyAppWidget.class);
+        int widgetId = mService.allocateAppWidgetId(mPkgName, HOST_ID);
+        assertTrue(mManager.bindAppWidgetIdIfAllowed(widgetId, provider));
+        assertEquals(provider, mManager.getAppWidgetInfo(widgetId).provider);
+
+        return widgetId;
+    }
+
+    private void flushMainThread() throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+        new Handler(mTestContext.getMainLooper()).post(latch::countDown);
+        latch.await();
+    }
+
     private class TestContext extends ContextWrapper {
 
         public TestContext() {
@@ -125,5 +274,15 @@
         public void unregisterReceiver(BroadcastReceiver receiver) {
             // ignore.
         }
+
+        @Override
+        public void enforceCallingOrSelfPermission(String permission, String message) {
+            // ignore.
+        }
+
+        @Override
+        public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+            // ignore.
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index c3eb09d..8da47c8 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -15,6 +15,10 @@
  */
 package com.android.server.devicepolicy;
 
+import static android.os.UserManagerInternal.CAMERA_DISABLED_GLOBALLY;
+import static android.os.UserManagerInternal.CAMERA_DISABLED_LOCALLY;
+import static android.os.UserManagerInternal.CAMERA_NOT_DISABLED;
+
 import android.Manifest.permission;
 import android.app.Activity;
 import android.app.admin.DeviceAdminReceiver;
@@ -39,6 +43,7 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.provider.Settings;
 import android.telephony.TelephonyManager;
 import android.test.MoreAsserts;
@@ -61,9 +66,11 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.TimeUnit;
 
 import static org.mockito.Matchers.any;
 import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyLong;
 import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
@@ -928,9 +935,8 @@
 
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(),
-                MockUtils.checkUserRestrictions()
-        );
+                eq(null),
+                eq(true), eq(CAMERA_NOT_DISABLED));
 
         assertFalse(dpm.isAdminActiveAsUser(admin1, UserHandle.USER_SYSTEM));
 
@@ -1287,7 +1293,8 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(defaultRestrictions),
-                MockUtils.checkUserRestrictions()
+                eq(true) /* isDeviceOwner */,
+                eq(CAMERA_NOT_DISABLED)
         );
         reset(mContext.userManagerInternal);
 
@@ -1296,21 +1303,21 @@
         }
 
         assertNoDeviceOwnerRestrictions();
+        reset(mContext.userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(),
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
-        );
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
-        );
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS,
+                        UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1328,8 +1335,7 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
-                MockUtils.checkUserRestrictions()
-        );
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1345,8 +1351,7 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(),
-                MockUtils.checkUserRestrictions()
-        );
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         assertNoDeviceOwnerRestrictions();
@@ -1358,42 +1363,38 @@
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
-                        UserManager.DISALLOW_UNMUTE_MICROPHONE)
-        );
+                        UserManager.DISALLOW_UNMUTE_MICROPHONE),
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_ADJUST_VOLUME);
         dpm.clearUserRestriction(admin1, UserManager.DISALLOW_UNMUTE_MICROPHONE);
-
+        reset(mContext.userManagerInternal);
 
         // More tests.
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_ADD_USER);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(),
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER)
-        );
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_FUN);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                MockUtils.checkUserRestrictions(),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
-                        UserManager.DISALLOW_ADD_USER)
-        );
+                        UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.setCameraDisabled(admin1, true);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 // DISALLOW_CAMERA will be applied to both local and global.
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
-                        UserManager.DISALLOW_CAMERA, UserManager.DISALLOW_ADD_USER)
-        );
+                        UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_DISABLED_GLOBALLY));
         reset(mContext.userManagerInternal);
 
         // Set up another DA and let it disable camera.  Now DISALLOW_CAMERA will only be applied
@@ -1407,11 +1408,10 @@
 
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
-                // DISALLOW_CAMERA will be applied to both local and global.
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA),
+                // DISALLOW_CAMERA will be applied to both local and global. <- TODO: fix this
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_FUN,
-                        UserManager.DISALLOW_ADD_USER)
-        );
+                        UserManager.DISALLOW_ADD_USER),
+                eq(true), eq(CAMERA_DISABLED_LOCALLY));
         reset(mContext.userManagerInternal);
         // TODO Make sure restrictions are written to the file.
     }
@@ -1429,8 +1429,7 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
@@ -1438,8 +1437,7 @@
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
                         UserManager.DISALLOW_OUTGOING_CALLS),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1462,8 +1460,7 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1484,8 +1481,7 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         DpmTestUtils.assertRestrictions(
@@ -1507,18 +1503,15 @@
                 eq(DpmMockContext.CALLER_USER_HANDLE),
                 MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
                         UserManager.DISALLOW_UNMUTE_MICROPHONE),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_NOT_DISABLED));
         reset(mContext.userManagerInternal);
 
         dpm.setCameraDisabled(admin1, true);
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(DpmMockContext.CALLER_USER_HANDLE),
-                MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA,
-                        UserManager.DISALLOW_ADJUST_VOLUME,
+                MockUtils.checkUserRestrictions(UserManager.DISALLOW_ADJUST_VOLUME,
                         UserManager.DISALLOW_UNMUTE_MICROPHONE),
-                isNull(Bundle.class)
-        );
+                eq(false), eq(CAMERA_DISABLED_LOCALLY));
         reset(mContext.userManagerInternal);
 
         // TODO Make sure restrictions are written to the file.
@@ -1558,7 +1551,8 @@
         verify(mContext.userManagerInternal).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(defaultRestrictions),
-                MockUtils.checkUserRestrictions()
+                eq(true) /* isDeviceOwner */,
+                eq(CAMERA_NOT_DISABLED)
         );
         reset(mContext.userManagerInternal);
 
@@ -1600,7 +1594,8 @@
             verify(mContext.userManagerInternal, atLeast(1)).setDevicePolicyUserRestrictions(
                 eq(UserHandle.USER_SYSTEM),
                 MockUtils.checkUserRestrictions(newDefaultEnabledRestriction),
-                MockUtils.checkUserRestrictions()
+                eq(true) /* isDeviceOwner */,
+                eq(CAMERA_NOT_DISABLED)
             );
             reset(mContext.userManagerInternal);
 
@@ -2124,8 +2119,37 @@
         setupDeviceOwner();
         mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
 
-        final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = 1 * 60 * 60 * 1000; // 1h
-        final long ONE_MINUTE = 60 * 1000;
+        final long MINIMUM_STRONG_AUTH_TIMEOUT_MS = TimeUnit.HOURS.toMillis(1);
+        final long ONE_MINUTE = TimeUnit.MINUTES.toMillis(1);
+        final long MIN_PLUS_ONE_MINUTE = MINIMUM_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE;
+        final long MAX_MINUS_ONE_MINUTE = DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS
+                - ONE_MINUTE;
+
+        // verify that the minimum timeout cannot be modified on user builds (system property is
+        // not being read)
+        mContext.buildMock.isDebuggable = false;
+
+        dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MAX_MINUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE);
+
+        verify(mContext.systemProperties, never()).getLong(anyString(), anyLong());
+
+        // restore to the debuggable build state
+        mContext.buildMock.isDebuggable = true;
+
+        // Always return the default (second arg) when getting system property for long type
+        when(mContext.systemProperties.getLong(anyString(), anyLong())).thenAnswer(
+                new Answer<Long>() {
+                    @Override
+                    public Long answer(InvocationOnMock invocation) throws Throwable {
+                        return (Long) invocation.getArguments()[1];
+                    }
+                }
+        );
+
+        // reset to default (0 means the admin is not participating, so default should be returned)
+        dpm.setRequiredStrongAuthTimeout(admin1, 0);
 
         // aggregation should be the default if unset by any admin
         assertEquals(dpm.getRequiredStrongAuthTimeout(null),
@@ -2142,7 +2166,7 @@
         assertEquals(dpm.getRequiredStrongAuthTimeout(null),
                 DevicePolicyManager.DEFAULT_STRONG_AUTH_TIMEOUT_MS);
 
-        // 0 means default
+        // 0 means the admin is not participating, so default should be returned
         dpm.setRequiredStrongAuthTimeout(admin1, 0);
         assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), 0);
         assertEquals(dpm.getRequiredStrongAuthTimeout(null),
@@ -2153,12 +2177,14 @@
         assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS);
         assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS);
 
-        // value within range
-        dpm.setRequiredStrongAuthTimeout(admin1, MINIMUM_STRONG_AUTH_TIMEOUT_MS + ONE_MINUTE);
-        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MINIMUM_STRONG_AUTH_TIMEOUT_MS
-                + ONE_MINUTE);
-        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MINIMUM_STRONG_AUTH_TIMEOUT_MS
-                + ONE_MINUTE);
+        // values within range
+        dpm.setRequiredStrongAuthTimeout(admin1, MIN_PLUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MIN_PLUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MIN_PLUS_ONE_MINUTE);
+
+        dpm.setRequiredStrongAuthTimeout(admin1, MAX_MINUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(admin1), MAX_MINUS_ONE_MINUTE);
+        assertEquals(dpm.getRequiredStrongAuthTimeout(null), MAX_MINUS_ONE_MINUTE);
 
         // reset to default
         dpm.setRequiredStrongAuthTimeout(admin1, 0);
@@ -3207,6 +3233,48 @@
         }
     }
 
+    public void testGetPermissionGrantState() throws Exception {
+        final String permission = "some.permission";
+        final String app1 = "com.example.app1";
+        final String app2 = "com.example.app2";
+
+        when(mContext.ipackageManager.checkPermission(eq(permission), eq(app1), anyInt()))
+                .thenReturn(PackageManager.PERMISSION_GRANTED);
+        doReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED).when(mContext.packageManager)
+                .getPermissionFlags(permission, app1, UserHandle.SYSTEM);
+        when(mContext.packageManager.getPermissionFlags(permission, app1,
+                UserHandle.of(DpmMockContext.CALLER_USER_HANDLE)))
+                .thenReturn(PackageManager.FLAG_PERMISSION_POLICY_FIXED);
+        when(mContext.ipackageManager.checkPermission(eq(permission), eq(app2), anyInt()))
+                .thenReturn(PackageManager.PERMISSION_DENIED);
+        doReturn(0).when(mContext.packageManager).getPermissionFlags(permission, app2,
+                UserHandle.SYSTEM);
+        when(mContext.packageManager.getPermissionFlags(permission, app2,
+                UserHandle.of(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(0);
+
+        // System can retrieve permission grant state.
+        mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED,
+                dpm.getPermissionGrantState(null, app1, permission));
+        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT,
+                dpm.getPermissionGrantState(null, app2, permission));
+
+        // A regular app cannot retrieve permission grant state.
+        mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        try {
+            dpm.getPermissionGrantState(null, app1, permission);
+            fail("Didn't throw IllegalStateException");
+        } catch (IllegalStateException expected) {
+        }
+
+        // Profile owner can retrieve permission grant state.
+        setAsProfileOwner(admin1);
+        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED,
+                dpm.getPermissionGrantState(admin1, app1, permission));
+        assertEquals(DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT,
+                dpm.getPermissionGrantState(admin1, app2, permission));
+    }
+
     private void setUserSetupCompleteForUser(boolean isUserSetupComplete, int userhandle) {
         when(mContext.settings.settingsSecureGetIntForUser(Settings.Secure.USER_SETUP_COMPLETE, 0,
                 userhandle)).thenReturn(isUserSetupComplete ? 1 : 0);
diff --git a/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
index 5ab9020..b5a6178 100644
--- a/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/InstallerTest.java
@@ -80,11 +80,19 @@
     }
 
     public void testGetAppSize() throws Exception {
+        int[] appIds = null;
+
         final PackageManager pm = getContext().getPackageManager();
         for (ApplicationInfo app : pm.getInstalledApplications(0)) {
             final int userId = UserHandle.getUserId(app.uid);
             final int appId = UserHandle.getAppId(app.uid);
 
+            if (ArrayUtils.contains(appIds, appId)) {
+                continue;
+            } else {
+                appIds = ArrayUtils.appendInt(appIds, appId);
+            }
+
             final String[] packageNames = pm.getPackagesForUid(app.uid);
             final long[] ceDataInodes = new long[packageNames.length];
             final String[] codePaths = new String[packageNames.length];
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java
new file mode 100644
index 0000000..ca1e6af
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest10.java
@@ -0,0 +1,183 @@
+/*
+ * 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.pm;
+
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils
+        .assertExpectException;
+import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.LauncherActivityInfo;
+import android.content.pm.LauncherApps.PinItemRequest;
+import android.content.pm.ShortcutInfo;
+import android.content.pm.ShortcutManager;
+import android.os.Process;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import static org.mockito.Mockito.*;
+
+/**
+ * Tests for {@link ShortcutManager#createShortcutResultIntent(ShortcutInfo)} and relevant APIs.
+ *
+ m FrameworksServicesTests &&
+ adb install \
+ -r -g ${ANDROID_PRODUCT_OUT}/data/app/FrameworksServicesTests/FrameworksServicesTests.apk &&
+ adb shell am instrument -e class com.android.server.pm.ShortcutManagerTest10 \
+ -w com.android.frameworks.servicestests/android.support.test.runner.AndroidJUnitRunner
+ */
+@SmallTest
+public class ShortcutManagerTest10 extends BaseShortcutManagerTest {
+
+    private PinItemRequest mRequest;
+
+    private PinItemRequest verifyAndGetCreateShortcutResult(Intent resultIntent) {
+        PinItemRequest request = mLauncherApps.getPinItemRequest(resultIntent);
+        assertNotNull(request);
+        assertEquals(PinItemRequest.REQUEST_TYPE_SHORTCUT, request.getRequestType());
+        return request;
+    }
+
+    public void testCreateShortcutResult_noDefaultLauncher() {
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            assertNull(mManager.createShortcutResultIntent(s1));
+        });
+    }
+
+    public void testCreateShortcutResult_validResult() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            Intent intent = mManager.createShortcutResultIntent(s1);
+            mRequest = verifyAndGetCreateShortcutResult(intent);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertTrue(mRequest.isValid());
+            assertTrue(mRequest.accept());
+        });
+    }
+
+    public void testCreateShortcutResult_alreadyPinned() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
+        });
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            Intent intent = mManager.createShortcutResultIntent(s1);
+            mRequest = verifyAndGetCreateShortcutResult(intent);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertTrue(mRequest.isValid());
+            assertTrue(mRequest.getShortcutInfo().isPinned());
+            assertTrue(mRequest.accept());
+        });
+    }
+
+    public void testCreateShortcutResult_alreadyPinnedByAnother() {
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            assertTrue(mManager.setDynamicShortcuts(list(makeShortcut("s1"))));
+        });
+
+        // Initially all launchers have the shortcut permission, until we call setDefaultLauncher().
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_P0);
+        });
+
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            Intent intent = mManager.createShortcutResultIntent(s1);
+            mRequest = verifyAndGetCreateShortcutResult(intent);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertTrue(mRequest.isValid());
+            assertFalse(mRequest.getShortcutInfo().isPinned());
+            assertTrue(mRequest.accept());
+        });
+    }
+
+    public void testCreateShortcutResult_defaultLauncherChanges() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            Intent intent = mManager.createShortcutResultIntent(s1);
+            mRequest = verifyAndGetCreateShortcutResult(intent);
+        });
+
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_2, USER_0));
+        // Verify that other launcher can't use this request
+        runWithCaller(LAUNCHER_2, USER_0, () -> {
+            assertFalse(mRequest.isValid());
+            assertExpectException(SecurityException.class, "Calling uid mismatch",
+                    mRequest::accept);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Set some random caller UID.
+            mInjectedCallingUid = 12345;
+
+            assertFalse(mRequest.isValid());
+            assertExpectException(SecurityException.class, "Calling uid mismatch",
+                    mRequest::accept);
+        });
+
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertTrue(mRequest.isValid());
+            assertTrue(mRequest.accept());
+        });
+    }
+
+    private LauncherActivityInfo setupMockActivityInfo() {
+        doReturn(getTestContext().getPackageName()).when(mServiceContext).getPackageName();
+        doReturn(getTestContext().getContentResolver()).when(mServiceContext).getContentResolver();
+
+        LauncherActivityInfo info = mock(LauncherActivityInfo.class);
+        when(info.getComponentName()).thenReturn(
+                new ComponentName(getTestContext(), "a.ShortcutConfigActivity"));
+        when(info.getUser()).thenReturn(Process.myUserHandle());
+        return info;
+    }
+
+    public void testStartConfigActivity_defaultLauncher() {
+        LauncherActivityInfo info = setupMockActivityInfo();
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        runWithCaller(LAUNCHER_1, USER_0, () ->
+            assertNotNull(mLauncherApps.getShortcutConfigActivityIntent(info))
+        );
+    }
+
+    public void testStartConfigActivity_nonDefaultLauncher() {
+        LauncherActivityInfo info = setupMockActivityInfo();
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+        runWithCaller(LAUNCHER_2, USER_0, () ->
+            assertExpectException(SecurityException.class, null, () ->
+                    mLauncherApps.getShortcutConfigActivityIntent(info))
+        );
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
index bcd72fc..df275d2 100644
--- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
+++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest8.java
@@ -1421,6 +1421,35 @@
         });
     }
 
+    public void testRequestPinShortcut_wrongLauncherCannotAccept() {
+        setDefaultLauncher(USER_0, mMainActivityFetcher.apply(LAUNCHER_1, USER_0));
+
+        runWithCaller(CALLING_PACKAGE_1, USER_P0, () -> {
+            ShortcutInfo s1 = makeShortcut("s1");
+            assertTrue(mManager.requestPinShortcut(s1, null));
+            verify(mServiceContext, times(0)).sendIntentSender(any(IntentSender.class));
+        });
+
+        final ArgumentCaptor<Intent> intent = ArgumentCaptor.forClass(Intent.class);
+        verify(mServiceContext).startActivityAsUser(intent.capture(), eq(HANDLE_USER_0));
+        final PinItemRequest request = mLauncherApps.getPinItemRequest(intent.getValue());
+
+        // Verify that other launcher can't use this request
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            // Set some random caller UID.
+            mInjectedCallingUid = 12345;
+
+            assertFalse(request.isValid());
+            assertExpectException(SecurityException.class, "Calling uid mismatch", request::accept);
+        });
+
+        // The default launcher can still use this request
+        runWithCaller(LAUNCHER_1, USER_0, () -> {
+            assertTrue(request.isValid());
+            assertTrue(request.accept());
+        });
+    }
+
     // TODO More tests:
 
     // Cancel previous pending request and release memory?
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java
index ad514cf..929a73d 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceCreateProfileTest.java
@@ -16,27 +16,27 @@
 
 package com.android.server.pm;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
 import android.app.ApplicationPackageManager;
 import android.content.pm.UserInfo;
 import android.os.Looper;
-import android.os.UserManagerInternal;
 import android.os.UserHandle;
+import android.os.UserManagerInternal;
 import android.support.test.InstrumentationRegistry;
-import android.support.test.runner.AndroidJUnit4;
 import android.support.test.filters.MediumTest;
+import android.support.test.runner.AndroidJUnit4;
 
 import com.android.server.LocalServices;
 
+import java.util.List;
+
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.util.List;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
 /**
  * <p>Run with:<pre>
  * runtest -c com.android.server.pm.UserManagerServiceCreateProfileTest frameworks-services
@@ -64,101 +64,90 @@
                 UserHandle.USER_SYSTEM, users.get(0).id);
     }
 
+    @After
+    public void tearDown() {
+        removeUsers();
+    }
+
     @Test
     public void testGetProfiles() {
-        try {
-            // Pretend we have a secondary user with a profile.
-            UserInfo secondaryUser = addUser();
-            UserInfo profile = addProfile(secondaryUser);
+        // Pretend we have a secondary user with a profile.
+        UserInfo secondaryUser = addUser();
+        UserInfo profile = addProfile(secondaryUser);
 
-            // System user should still have no profile so getProfiles should just return 1 user.
-            List<UserInfo> users =
-                    mUserManagerService.getProfiles(UserHandle.USER_SYSTEM, /*excludeDying*/ false);
-            assertEquals("Profiles returned where none should exist", 1, users.size());
-            assertEquals("Missing system user from profile list of system user",
-                    UserHandle.USER_SYSTEM, users.get(0).id);
+        // System user should still have no profile so getProfiles should just return 1 user.
+        List<UserInfo> users =
+                mUserManagerService.getProfiles(UserHandle.USER_SYSTEM, /*excludeDying*/ false);
+        assertEquals("Profiles returned where none should exist", 1, users.size());
+        assertEquals("Missing system user from profile list of system user",
+                UserHandle.USER_SYSTEM, users.get(0).id);
 
-            // Secondary user should have 1 profile, so return that and itself.
-            users = mUserManagerService.getProfiles(secondaryUser.id, /*excludeDying*/ false);
-            assertEquals("Profiles returned where none should exist", 2, users.size());
-            assertTrue("Missing secondary user id", users.get(0).id == secondaryUser.id
-                    || users.get(1).id == secondaryUser.id);
-            assertTrue("Missing profile user id", users.get(0).id == profile.id
-                    || users.get(1).id == profile.id);
-        } finally {
-            removeUsers();
-        }
+        // Secondary user should have 1 profile, so return that and itself.
+        users = mUserManagerService.getProfiles(secondaryUser.id, /*excludeDying*/ false);
+        assertEquals("Profiles returned where none should exist", 2, users.size());
+        assertTrue("Missing secondary user id", users.get(0).id == secondaryUser.id
+                || users.get(1).id == secondaryUser.id);
+        assertTrue("Missing profile user id", users.get(0).id == profile.id
+                || users.get(1).id == profile.id);
     }
 
     @Test
     public void testProfileBadge() {
-        try {
-            // First profile for system user should get badge 0
-            assertEquals("First profile isn't given badge index 0", 0,
-                    mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
+        // First profile for system user should get badge 0
+        assertEquals("First profile isn't given badge index 0", 0,
+                mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
 
-            // Pretend we have a secondary user.
-            UserInfo secondaryUser = addUser();
+        // Pretend we have a secondary user.
+        UserInfo secondaryUser = addUser();
 
-            // Check first profile badge for secondary user is also 0.
-            assertEquals("First profile for secondary user isn't given badge index 0", 0,
-                    mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
+        // Check first profile badge for secondary user is also 0.
+        assertEquals("First profile for secondary user isn't given badge index 0", 0,
+                mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
 
-            // Shouldn't impact the badge for profile in system user
-            assertEquals("First profile isn't given badge index 0 with secondary user", 0,
-                    mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
+        // Shouldn't impact the badge for profile in system user
+        assertEquals("First profile isn't given badge index 0 with secondary user", 0,
+                mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
 
-            // Pretend a secondary user has a profile.
-            addProfile(secondaryUser);
+        // Pretend a secondary user has a profile.
+        addProfile(secondaryUser);
 
-            // Shouldn't have impacted the badge for the system user
-            assertEquals("First profile isn't given badge index 0 in secondary user", 0,
-                    mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
-        } finally {
-            removeUsers();
-        }
+        // Shouldn't have impacted the badge for the system user
+        assertEquals("First profile isn't given badge index 0 in secondary user", 0,
+                mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM));
     }
 
     @Test
     public void testProfileBadgeUnique() {
-        try {
-            List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
-            UserInfo system = users.get(0);
-            // Badges should get allocated 0 -> max
-            for (int i = 0; i < UserManagerService.getMaxManagedProfiles(); ++i) {
-                int nextBadge = mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM);
-                assertEquals("Wrong badge allocated", i, nextBadge);
-                UserInfo profile = addProfile(system);
-                profile.profileBadge = nextBadge;
-            }
-        } finally {
-            removeUsers();
+        List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
+        UserInfo system = users.get(0);
+        // Badges should get allocated 0 -> max
+        for (int i = 0; i < UserManagerService.getMaxManagedProfiles(); ++i) {
+            int nextBadge = mUserManagerService.getFreeProfileBadgeLU(UserHandle.USER_SYSTEM);
+            assertEquals("Wrong badge allocated", i, nextBadge);
+            UserInfo profile = addProfile(system);
+            profile.profileBadge = nextBadge;
         }
     }
 
     @Test
     public void testProfileBadgeReuse() {
-        try {
-            // Pretend we have a secondary user with a profile.
-            UserInfo secondaryUser = addUser();
-            UserInfo profile = addProfile(secondaryUser);
-            // Add the profile it to the users being removed.
-            mUserManagerService.addRemovingUserIdLocked(profile.id);
-            // We should reuse the badge from the profile being removed.
-            assertEquals("Badge index not reused while removing a user", 0,
-                    mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
+        // Pretend we have a secondary user with a profile.
+        UserInfo secondaryUser = addUser();
+        UserInfo profile = addProfile(secondaryUser);
+        // Add the profile it to the users being removed.
+        mUserManagerService.addRemovingUserIdLocked(profile.id);
+        // We should reuse the badge from the profile being removed.
+        assertEquals("Badge index not reused while removing a user", 0,
+                mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
 
-            // Edge case of reuse that only applies if we ever support 3 managed profiles
-            // We should prioritise using lower badge indexes
-            if (UserManagerService.getMaxManagedProfiles() > 2) {
-                UserInfo profileBadgeOne = addProfile(secondaryUser);
-                profileBadgeOne.profileBadge = 1;
-                // 0 and 2 are free, we should reuse 0 rather than 2.
-                assertEquals("Lower index not used", 0,
-                        mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
-            }
-        } finally {
-            removeUsers();
+        // Edge case of reuse that only applies if we ever support 3 managed profiles
+        // We should prioritise using lower badge indexes
+        if (UserManagerService.getMaxManagedProfiles() > 2) {
+            UserInfo profileBadgeOne = addProfile(secondaryUser);
+            profileBadgeOne.profileBadge = 1;
+            // 0 and 2 are free, we should reuse 0 rather than 2.
+            assertEquals("Lower index not used", 0,
+                    mUserManagerService.getFreeProfileBadgeLU(secondaryUser.id));
         }
     }
 
@@ -172,6 +161,49 @@
                 ApplicationPackageManager.CORP_BADGE_LABEL_RES_ID.length);
     }
 
+    @Test
+    public void testCanAddMoreManagedProfiles_removeProfile() {
+        // if device is low-ram or doesn't support managed profiles for some other reason, just
+        // skip the test
+        if (!mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
+                false /* disallow remove */)) {
+            return;
+        }
+
+        // GIVEN we've reached the limit of managed profiles possible on the system user
+        while (mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
+                false /* disallow remove */)) {
+            addProfile(mUserManagerService.getPrimaryUser());
+        }
+
+        // THEN you should be able to add a new profile if you remove an existing one
+        assertTrue("Cannot add a managed profile by removing another one",
+                mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
+                        true /* allow remove */));
+    }
+
+    @Test
+    public void testCanAddMoreManagedProfiles_removeDisabledProfile() {
+        // if device is low-ram or doesn't support managed profiles for some other reason, just
+        // skip the test
+        if (!mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
+                false /* disallow remove */)) {
+            return;
+        }
+
+        // GIVEN we've reached the limit of managed profiles possible on the system user
+        // GIVEN that the profiles are not enabled yet
+        while (mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
+                false /* disallow remove */)) {
+            addProfile(mUserManagerService.getPrimaryUser(), true /* disabled */);
+        }
+
+        // THEN you should be able to add a new profile if you remove an existing one
+        assertTrue("Cannot add a managed profile by removing another one",
+                mUserManagerService.canAddMoreManagedProfiles(UserHandle.USER_SYSTEM,
+                        true /* allow remove */));
+    }
+
     private void removeUsers() {
         List<UserInfo> users = mUserManagerService.getUsers(/* excludeDying */ false);
         for (UserInfo user: users) {
@@ -182,10 +214,17 @@
     }
 
     private UserInfo addProfile(UserInfo user) {
+        return addProfile(user, false);
+    }
+
+    private UserInfo addProfile(UserInfo user, boolean disabled) {
         user.profileGroupId = user.id;
+        int flags = UserInfo.FLAG_MANAGED_PROFILE;
+        if (disabled) {
+            flags |= UserInfo.FLAG_DISABLED;
+        }
         UserInfo profile = new UserInfo(
-                mUserManagerService.getNextAvailableId(), "profile",
-                UserInfo.FLAG_MANAGED_PROFILE);
+                mUserManagerService.getNextAvailableId(), "profile", flags);
         profile.profileGroupId = user.id;
         mUserManagerService.putUserInfo(profile);
         return profile;
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
index 11f9ebb..480be2e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserRestrictionsUtilsTest.java
@@ -16,13 +16,16 @@
 
 package com.android.server.pm;
 
+import static com.android.server.devicepolicy.DpmTestUtils.assertRestrictions;
+import static com.android.server.devicepolicy.DpmTestUtils.newRestrictions;
+
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.UserManagerInternal;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
-
-import com.android.server.devicepolicy.DpmTestUtils;
+import android.util.SparseArray;
 
 /**
  * Tests for {@link com.android.server.pm.UserRestrictionsUtils}.
@@ -49,14 +52,14 @@
     public void testIsEmpty() {
         assertTrue(UserRestrictionsUtils.isEmpty(null));
         assertTrue(UserRestrictionsUtils.isEmpty(new Bundle()));
-        assertFalse(UserRestrictionsUtils.isEmpty(DpmTestUtils.newRestrictions("a")));
+        assertFalse(UserRestrictionsUtils.isEmpty(newRestrictions("a")));
     }
 
     public void testClone() {
         Bundle in = new Bundle();
         Bundle out = UserRestrictionsUtils.clone(in);
         assertNotSame(in, out);
-        DpmTestUtils.assertRestrictions(out, new Bundle());
+        assertRestrictions(out, new Bundle());
 
         out = UserRestrictionsUtils.clone(null);
         assertNotNull(out);
@@ -64,16 +67,16 @@
     }
 
     public void testMerge() {
-        Bundle a = DpmTestUtils.newRestrictions("a", "d");
-        Bundle b = DpmTestUtils.newRestrictions("b", "d", "e");
+        Bundle a = newRestrictions("a", "d");
+        Bundle b = newRestrictions("b", "d", "e");
 
         UserRestrictionsUtils.merge(a, b);
 
-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions("a", "b", "d", "e"), a);
+        assertRestrictions(newRestrictions("a", "b", "d", "e"), a);
 
         UserRestrictionsUtils.merge(a, null);
 
-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions("a", "b", "d", "e"), a);
+        assertRestrictions(newRestrictions("a", "b", "d", "e"), a);
 
         try {
             UserRestrictionsUtils.merge(a, a);
@@ -114,25 +117,32 @@
         final Bundle local = new Bundle();
         final Bundle global = new Bundle();
 
-        UserRestrictionsUtils.sortToGlobalAndLocal(null, global, local);
+        UserRestrictionsUtils.sortToGlobalAndLocal(null, false /* isDeviceOwner */,
+                UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
         assertEquals(0, global.size());
         assertEquals(0, local.size());
 
-        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, global, local);
+        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false /* isDeviceOwner */,
+                UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
         assertEquals(0, global.size());
         assertEquals(0, local.size());
 
-        UserRestrictionsUtils.sortToGlobalAndLocal(DpmTestUtils.newRestrictions(
+        // Restrictions set by DO.
+        UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
                 UserManager.DISALLOW_ADJUST_VOLUME,
                 UserManager.DISALLOW_UNMUTE_MICROPHONE,
                 UserManager.DISALLOW_USB_FILE_TRANSFER,
                 UserManager.DISALLOW_CONFIG_TETHERING,
                 UserManager.DISALLOW_OUTGOING_BEAM,
-                UserManager.DISALLOW_APPS_CONTROL
-        ), global, local);
+                UserManager.DISALLOW_APPS_CONTROL,
+                UserManager.ENSURE_VERIFY_APPS
+        ), true /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
 
 
-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(
+        assertRestrictions(newRestrictions(
+                // This one is global no matter who sets it.
+                UserManager.ENSURE_VERIFY_APPS,
+
                 // These can be set by PO too, but when DO sets them, they're global.
                 UserManager.DISALLOW_ADJUST_VOLUME,
                 UserManager.DISALLOW_UNMUTE_MICROPHONE,
@@ -142,11 +152,117 @@
                 UserManager.DISALLOW_CONFIG_TETHERING
         ), global);
 
-        DpmTestUtils.assertRestrictions(DpmTestUtils.newRestrictions(
+        assertRestrictions(newRestrictions(
                 // They can be set by both DO/PO.
                 UserManager.DISALLOW_OUTGOING_BEAM,
                 UserManager.DISALLOW_APPS_CONTROL
         ), local);
+
+        local.clear();
+        global.clear();
+
+        // Restrictions set by PO.
+        UserRestrictionsUtils.sortToGlobalAndLocal(newRestrictions(
+                UserManager.DISALLOW_ADJUST_VOLUME,
+                UserManager.DISALLOW_UNMUTE_MICROPHONE,
+                UserManager.DISALLOW_USB_FILE_TRANSFER,
+                UserManager.DISALLOW_CONFIG_TETHERING,
+                UserManager.DISALLOW_OUTGOING_BEAM,
+                UserManager.DISALLOW_APPS_CONTROL,
+                UserManager.ENSURE_VERIFY_APPS
+        ), false /* isDeviceOwner */, UserManagerInternal.CAMERA_NOT_DISABLED, global, local);
+
+        assertRestrictions(newRestrictions(
+                // This one is global no matter who sets it.
+                UserManager.ENSURE_VERIFY_APPS
+        ), global);
+
+        assertRestrictions(newRestrictions(
+                // These can be set by PO too, but when PO sets them, they're local.
+                UserManager.DISALLOW_ADJUST_VOLUME,
+                UserManager.DISALLOW_UNMUTE_MICROPHONE,
+
+                // They can be set by both DO/PO.
+                UserManager.DISALLOW_OUTGOING_BEAM,
+                UserManager.DISALLOW_APPS_CONTROL,
+
+                // These can only be set by DO.
+                UserManager.DISALLOW_USB_FILE_TRANSFER,
+                UserManager.DISALLOW_CONFIG_TETHERING
+        ), local);
+
+    }
+
+    public void testSortToLocalAndGlobalWithCameraDisabled() {
+        final Bundle local = new Bundle();
+        final Bundle global = new Bundle();
+
+        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
+                UserManagerInternal.CAMERA_DISABLED_GLOBALLY, global, local);
+        assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), global);
+        assertEquals(0, local.size());
+        global.clear();
+
+        UserRestrictionsUtils.sortToGlobalAndLocal(Bundle.EMPTY, false,
+                UserManagerInternal.CAMERA_DISABLED_LOCALLY, global, local);
+        assertEquals(0, global.size());
+        assertRestrictions(newRestrictions(UserManager.DISALLOW_CAMERA), local);
+    }
+
+    public void testMergeAll() {
+        SparseArray<Bundle> restrictions = new SparseArray<>();
+        assertNull(UserRestrictionsUtils.mergeAll(restrictions));
+
+        restrictions.put(0, newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME));
+        restrictions.put(1, newRestrictions(UserManager.DISALLOW_USB_FILE_TRANSFER));
+        restrictions.put(2, newRestrictions(UserManager.DISALLOW_APPS_CONTROL));
+
+        Bundle result = UserRestrictionsUtils.mergeAll(restrictions);
+        assertRestrictions(
+                newRestrictions(
+                        UserManager.DISALLOW_ADJUST_VOLUME,
+                        UserManager.DISALLOW_USB_FILE_TRANSFER,
+                        UserManager.DISALLOW_APPS_CONTROL),
+                result);
+    }
+
+    public void testMoveRestriction() {
+        SparseArray<Bundle> localRestrictions = new SparseArray<>();
+        SparseArray<Bundle> globalRestrictions = new SparseArray<>();
+
+        // User 0 has only local restrictions, nothing should change.
+        localRestrictions.put(0, newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME));
+        // User 1 has a local restriction to be moved to global and some global already. Local
+        // restrictions should be removed for this user.
+        localRestrictions.put(1, newRestrictions(UserManager.ENSURE_VERIFY_APPS));
+        globalRestrictions.put(1, newRestrictions(UserManager.DISALLOW_ADD_USER));
+        // User 2 has a local restriction to be moved and one to leave local.
+        localRestrictions.put(2, newRestrictions(
+                UserManager.ENSURE_VERIFY_APPS,
+                UserManager.DISALLOW_CONFIG_VPN));
+
+        UserRestrictionsUtils.moveRestriction(
+                UserManager.ENSURE_VERIFY_APPS, localRestrictions, globalRestrictions);
+
+        // Check user 0.
+        assertRestrictions(
+                newRestrictions(UserManager.DISALLOW_ADJUST_VOLUME),
+                localRestrictions.get(0));
+        assertNull(globalRestrictions.get(0));
+
+        // Check user 1.
+        assertNull(localRestrictions.get(1));
+        assertRestrictions(
+                newRestrictions(UserManager.ENSURE_VERIFY_APPS, UserManager.DISALLOW_ADD_USER),
+                globalRestrictions.get(1));
+
+        // Check user 2.
+        assertRestrictions(
+                newRestrictions(UserManager.DISALLOW_CONFIG_VPN),
+                localRestrictions.get(2));
+        assertRestrictions(
+                newRestrictions(UserManager.ENSURE_VERIFY_APPS),
+                globalRestrictions.get(2));
     }
 
     public void testAreEqual() {
@@ -172,33 +288,33 @@
 
         assertFalse(UserRestrictionsUtils.areEqual(
                 null,
-                DpmTestUtils.newRestrictions("a")));
+                newRestrictions("a")));
 
         assertFalse(UserRestrictionsUtils.areEqual(
-                DpmTestUtils.newRestrictions("a"),
+                newRestrictions("a"),
                 null));
 
         assertTrue(UserRestrictionsUtils.areEqual(
-                DpmTestUtils.newRestrictions("a"),
-                DpmTestUtils.newRestrictions("a")));
+                newRestrictions("a"),
+                newRestrictions("a")));
 
         assertFalse(UserRestrictionsUtils.areEqual(
-                DpmTestUtils.newRestrictions("a"),
-                DpmTestUtils.newRestrictions("a", "b")));
+                newRestrictions("a"),
+                newRestrictions("a", "b")));
 
         assertFalse(UserRestrictionsUtils.areEqual(
-                DpmTestUtils.newRestrictions("a", "b"),
-                DpmTestUtils.newRestrictions("a")));
+                newRestrictions("a", "b"),
+                newRestrictions("a")));
 
         assertFalse(UserRestrictionsUtils.areEqual(
-                DpmTestUtils.newRestrictions("b", "a"),
-                DpmTestUtils.newRestrictions("a", "a")));
+                newRestrictions("b", "a"),
+                newRestrictions("a", "a")));
 
         // Make sure false restrictions are handled correctly.
-        final Bundle a = DpmTestUtils.newRestrictions("a");
+        final Bundle a = newRestrictions("a");
         a.putBoolean("b", true);
 
-        final Bundle b = DpmTestUtils.newRestrictions("a");
+        final Bundle b = newRestrictions("a");
         b.putBoolean("b", false);
 
         assertFalse(UserRestrictionsUtils.areEqual(a, b));
diff --git a/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java b/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
new file mode 100644
index 0000000..e2aff16
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/policy/AccessibilityShortcutControllerTest.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.policy;
+
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.os.Handler;
+import android.provider.Settings;
+import android.support.test.runner.AndroidJUnit4;
+
+import android.test.mock.MockContentResolver;
+import android.text.TextUtils;
+import android.view.Window;
+import android.view.WindowManager;
+import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.IAccessibilityManager;
+import android.widget.Toast;
+import com.android.internal.R;
+import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.policy.AccessibilityShortcutController.FrameworkObjectProvider;
+
+import org.junit.After;
+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;
+import org.mockito.internal.util.reflection.Whitebox;
+
+import java.util.Collections;
+
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN;
+import static android.provider.Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
+
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityShortcutControllerTest {
+    private static final String SERVICE_NAME_STRING = "fake.package/fake.service.name";
+
+    private @Mock Context mContext;
+    private @Mock FrameworkObjectProvider mFrameworkObjectProvider;
+    private @Mock IAccessibilityManager mAccessibilityManagerService;
+    private @Mock Handler mHandler;
+    private @Mock AlertDialog.Builder mAlertDialogBuilder;
+    private @Mock AlertDialog mAlertDialog;
+    private @Mock AccessibilityServiceInfo mServiceInfo;
+    private @Mock Resources mResources;
+    private @Mock Toast mToast;
+
+    private MockContentResolver mContentResolver;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mContentResolver = new MockContentResolver(mContext);
+        mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
+        when(mContext.getContentResolver()).thenReturn(mContentResolver);
+        when(mContext.getResources()).thenReturn(mResources);
+
+        when(mAccessibilityManagerService.getInstalledAccessibilityServiceList(anyInt()))
+                .thenReturn(Collections.singletonList(mServiceInfo));
+
+        // Use the extra level of indirection in the object to mock framework objects
+        AccessibilityManager accessibilityManager =
+                new AccessibilityManager(mHandler, mAccessibilityManagerService, 0);
+        when(mFrameworkObjectProvider.getAccessibilityManagerInstance(mContext))
+                .thenReturn(accessibilityManager);
+        when(mFrameworkObjectProvider.getAlertDialogBuilder(mContext))
+                .thenReturn(mAlertDialogBuilder);
+        when(mFrameworkObjectProvider.makeToastFromText(eq(mContext), anyObject(), anyInt()))
+                .thenReturn(mToast);
+
+        when(mResources.getString(anyInt())).thenReturn("Howdy %s");
+        ResolveInfo resolveInfo = mock(ResolveInfo.class);
+        when(resolveInfo.loadLabel(anyObject())).thenReturn("Service name");
+        when(mServiceInfo.getResolveInfo()).thenReturn(resolveInfo);
+        when(mServiceInfo.getComponentName())
+                .thenReturn(ComponentName.unflattenFromString(SERVICE_NAME_STRING));
+
+        when(mAlertDialogBuilder.setTitle(anyInt())).thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.setCancelable(anyBoolean())).thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.setMessage(anyObject())).thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.setPositiveButton(anyInt(), anyObject()))
+                .thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.setNegativeButton(anyInt(), anyObject()))
+                .thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.setOnCancelListener(anyObject())).thenReturn(mAlertDialogBuilder);
+        when(mAlertDialogBuilder.create()).thenReturn(mAlertDialog);
+
+        Window window = mock(Window.class);
+        Whitebox.setInternalState(window, "mWindowAttributes", new WindowManager.LayoutParams());
+        when(mAlertDialog.getWindow()).thenReturn(window);
+    }
+
+    @After
+    public void tearDown() {
+    }
+
+    @Test
+    public void testShortcutAvailable_withNullServiceIdWhenCreated_shouldReturnFalse() {
+        configureShortcutDisabled();
+        assertFalse(getController().isAccessibilityShortcutAvailable());
+    }
+
+    @Test
+    public void testShortcutAvailable_withNonNullServiceIdWhenCreated_shouldReturnTrue() {
+        configureShortcutEnabled();
+        assertTrue(getController().isAccessibilityShortcutAvailable());
+    }
+
+    @Test
+    public void testShortcutAvailable_whenServiceIdBecomesNull_shouldReturnFalse() {
+        configureShortcutEnabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
+        accessibilityShortcutController.onSettingsChanged();
+        assertFalse(accessibilityShortcutController.isAccessibilityShortcutAvailable());
+    }
+
+    @Test
+    public void testShortcutAvailable_whenServiceIdBecomesNonNull_shouldReturnTrue() {
+        configureShortcutDisabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        configureShortcutEnabled();
+        accessibilityShortcutController.onSettingsChanged();
+        assertTrue(accessibilityShortcutController.isAccessibilityShortcutAvailable());
+    }
+
+    @Test
+    public void testOnAccessibilityShortcut_firstTime_showsWarningDialog()
+            throws Exception {
+        configureShortcutEnabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        accessibilityShortcutController.performAccessibilityShortcut();
+
+        assertEquals(1, Settings.Secure.getInt(
+                mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0));
+        verify(mResources).getString(R.string.accessibility_shortcut_toogle_warning);
+        verify(mAlertDialog).show();
+        verify(mAccessibilityManagerService).getInstalledAccessibilityServiceList(anyInt());
+        verify(mAccessibilityManagerService, times(0)).performAccessibilityShortcut();
+    }
+
+    @Test
+    public void testOnAccessibilityShortcut_withDialogShowing_callsServer()
+        throws Exception {
+        configureShortcutEnabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        accessibilityShortcutController.performAccessibilityShortcut();
+        accessibilityShortcutController.performAccessibilityShortcut();
+        verify(mToast).show();
+        verify(mAccessibilityManagerService, times(1)).performAccessibilityShortcut();
+    }
+
+    @Test
+    public void testOnAccessibilityShortcut_ifCanceledFirstTime_showsWarningDialog()
+        throws Exception {
+        configureShortcutEnabled();
+        AccessibilityShortcutController accessibilityShortcutController = getController();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        accessibilityShortcutController.performAccessibilityShortcut();
+        ArgumentCaptor<AlertDialog.OnCancelListener> cancelListenerCaptor =
+                ArgumentCaptor.forClass(AlertDialog.OnCancelListener.class);
+        verify(mAlertDialogBuilder).setOnCancelListener(cancelListenerCaptor.capture());
+        // Call the cancel callback
+        cancelListenerCaptor.getValue().onCancel(null);
+
+        accessibilityShortcutController.performAccessibilityShortcut();
+        verify(mAlertDialog, times(2)).show();
+    }
+
+    @Test
+    public void testClickingDisableButtonInDialog_shouldClearShortcutId() {
+        configureShortcutEnabled();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        getController().performAccessibilityShortcut();
+
+        ArgumentCaptor<DialogInterface.OnClickListener> captor =
+                ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
+        verify(mAlertDialogBuilder).setNegativeButton(eq(R.string.disable_accessibility_shortcut),
+                captor.capture());
+        // Call the button callback
+        captor.getValue().onClick(null, 0);
+        assertTrue(TextUtils.isEmpty(
+                Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE)));
+    }
+
+    @Test
+    public void testClickingLeaveOnButtonInDialog_shouldLeaveShortcutReady() throws Exception {
+        configureShortcutEnabled();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 0);
+        getController().performAccessibilityShortcut();
+
+        ArgumentCaptor<DialogInterface.OnClickListener> captor =
+            ArgumentCaptor.forClass(DialogInterface.OnClickListener.class);
+        verify(mAlertDialogBuilder).setPositiveButton(eq(R.string.leave_accessibility_shortcut_on),
+            captor.capture());
+        // Call the button callback, if one exists
+        if (captor.getValue() != null) {
+            captor.getValue().onClick(null, 0);
+        }
+        assertEquals(SERVICE_NAME_STRING,
+                Settings.Secure.getString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE));
+        assertEquals(1, Settings.Secure.getInt(
+            mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN));
+    }
+
+    @Test
+    public void testOnAccessibilityShortcut_afterDialogShown_shouldCallServer() throws Exception {
+        configureShortcutEnabled();
+        Settings.Secure.putInt(mContentResolver, ACCESSIBILITY_SHORTCUT_DIALOG_SHOWN, 1);
+        getController().performAccessibilityShortcut();
+
+        verifyZeroInteractions(mAlertDialogBuilder, mAlertDialog);
+        verify(mToast).show();
+        verify(mAccessibilityManagerService).performAccessibilityShortcut();
+    }
+
+    private void configureShortcutDisabled() {
+        Settings.Secure.putString(mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, "");
+    }
+
+    private void configureShortcutEnabled() {
+        Settings.Secure.putString(
+                mContentResolver, ACCESSIBILITY_SHORTCUT_TARGET_SERVICE, SERVICE_NAME_STRING);
+    }
+
+    private AccessibilityShortcutController getController() {
+        AccessibilityShortcutController accessibilityShortcutController =
+                new AccessibilityShortcutController(mContext, mHandler);
+        accessibilityShortcutController.mFrameworkObjectProvider = mFrameworkObjectProvider;
+        return accessibilityShortcutController;
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index d2512ac..83a61ca 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -19,7 +19,6 @@
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.database.ContentObserver;
 import android.webkit.WebViewProviderInfo;
 
 import java.util.HashMap;
@@ -31,6 +30,7 @@
     private boolean mFallbackLogicEnabled;
     private final int mNumRelros;
     private final boolean mIsDebuggable;
+    private int mMultiProcessSetting;
 
     public TestSystemImpl(WebViewProviderInfo[] packageConfigs, boolean fallbackLogicEnabled,
             int numRelros, boolean isDebuggable) {
@@ -121,8 +121,15 @@
     }
 
     @Override
-    public void setMultiProcessEnabledFromContext(Context context) {}
+    public int getMultiProcessSetting(Context context) {
+        return mMultiProcessSetting;
+    }
 
     @Override
-    public void registerContentObserver(Context context, ContentObserver contentObserver) {}
+    public void setMultiProcessSetting(Context context, int value) {
+        mMultiProcessSetting = value;
+    }
+
+    @Override
+    public void notifyZygote(boolean enableMultiProcess) {}
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
index 7f1c273..26accc3 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowContainerControllerTests.java
@@ -77,35 +77,8 @@
     }
 
     private TestAppWindowContainerController createAppWindowController() {
-        final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
         final TestTaskWindowContainerController taskController =
-                new TestTaskWindowContainerController(stack.mStackId);
-        final IApplicationToken token = new TestIApplicationToken();
-        return new TestAppWindowContainerController(taskController, token);
-    }
-
-    private class TestAppWindowContainerController extends AppWindowContainerController {
-
-        final IApplicationToken mToken;
-
-        TestAppWindowContainerController(TestTaskWindowContainerController taskController,
-                IApplicationToken token) {
-            super(taskController, token, null /* listener */, 0 /* index */,
-                    SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */,
-                    true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
-                    false /* launchTaskBehind */, false /* alwaysFocusable */,
-                    0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
-                    0 /* inputDispatchingTimeoutNanos */, sWm);
-            mToken = token;
-        }
-    }
-
-    private class TestIApplicationToken implements IApplicationToken {
-
-        private final Binder mBinder = new Binder();
-        @Override
-        public IBinder asBinder() {
-            return mBinder;
-        }
+                new TestTaskWindowContainerController();
+        return new TestAppWindowContainerController(taskController);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
index 06837d3..1d9875f 100644
--- a/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -22,7 +22,11 @@
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.Surface;
+import android.view.WindowManager;
 
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
@@ -83,4 +87,66 @@
         final WindowState window2 = createWindow(null, TYPE_APPLICATION_STARTING, token, "window2");
         assertEquals(window2, token.findMainWindow());
     }
+
+    @Test
+    public void testLandscapeSeascapeRotationByApp() throws Exception {
+        // Some plumbing to get the service ready for rotation updates.
+        sWm.mDisplayReady = true;
+        sWm.mDisplayEnabled = true;
+
+        // Create an app window with token on a display.
+        final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        final TestAppWindowToken appWindowToken = new TestAppWindowToken(sDisplayContent);
+        task.addChild(appWindowToken, 0);
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
+                TYPE_BASE_APPLICATION);
+        attrs.setTitle("AppWindow");
+        final TestWindowState appWindow = new TestWindowState(attrs, appWindowToken);
+        appWindowToken.addWindow(appWindow);
+
+        // Set initial orientation and update.
+        appWindowToken.setOrientation(SCREEN_ORIENTATION_LANDSCAPE);
+        sWm.updateOrientationFromAppTokens(sDisplayContent.getOverrideConfiguration(), null,
+                sDisplayContent.getDisplayId());
+        assertEquals(SCREEN_ORIENTATION_LANDSCAPE, sWm.mLastOrientation);
+        appWindow.resizeReported = false;
+
+        // Update the orientation to perform 180 degree rotation and check that resize was reported.
+        appWindowToken.setOrientation(SCREEN_ORIENTATION_REVERSE_LANDSCAPE);
+        sWm.updateOrientationFromAppTokens(sDisplayContent.getOverrideConfiguration(), null,
+                sDisplayContent.getDisplayId());
+        sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+        assertEquals(SCREEN_ORIENTATION_REVERSE_LANDSCAPE, sWm.mLastOrientation);
+        assertTrue(appWindow.resizeReported);
+    }
+
+    @Test
+    public void testLandscapeSeascapeRotationByPolicy() throws Exception {
+        // Some plumbing to get the service ready for rotation updates.
+        sWm.mDisplayReady = true;
+        sWm.mDisplayEnabled = true;
+
+        // Create an app window with token on a display.
+        final TaskStack stack = createTaskStackOnDisplay(sDisplayContent);
+        final Task task = createTaskInStack(stack, 0 /* userId */);
+        final TestAppWindowToken appWindowToken = new TestAppWindowToken(sDisplayContent);
+        task.addChild(appWindowToken, 0);
+        final WindowManager.LayoutParams attrs = new WindowManager.LayoutParams(
+                TYPE_BASE_APPLICATION);
+        attrs.setTitle("AppWindow");
+        final TestWindowState appWindow = new TestWindowState(attrs, appWindowToken);
+        appWindowToken.addWindow(appWindow);
+
+        // Set initial orientation and update.
+        ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = Surface.ROTATION_90;
+        sWm.updateRotation(false, false);
+        appWindow.resizeReported = false;
+
+        // Update the rotation to perform 180 degree rotation and check that resize was reported.
+        ((TestWindowManagerPolicy) sWm.mPolicy).rotationToReport = Surface.ROTATION_270;
+        sWm.updateRotation(false, false);
+        sWm.mRoot.performSurfacePlacement(false /* recoveringMemory */);
+        assertTrue(appWindow.resizeReported);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
new file mode 100644
index 0000000..48d4770
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskSnapshotCacheTest.java
@@ -0,0 +1,64 @@
+/*
+ * 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.wm;
+
+import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
+import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER;
+import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_NEVER;
+import static android.graphics.GraphicBuffer.create;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+
+import android.app.ActivityManager.TaskSnapshot;
+import android.content.res.Configuration;
+import android.graphics.GraphicBuffer;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test class for {@link TaskSnapshotCache}.
+ *
+ * runtest frameworks-services -c com.android.server.wm.TaskSnapshotCacheTest
+ */
+@SmallTest
+@Presubmit
+@RunWith(AndroidJUnit4.class)
+public class TaskSnapshotCacheTest extends WindowTestsBase {
+
+    @Test
+    public void testCleanCache() throws Exception {
+        TaskSnapshotCache snapshotCache = new TaskSnapshotCache();
+        final WindowState window = createWindow(null, FIRST_APPLICATION_WINDOW, "window");
+        snapshotCache.putSnapshot(window.getTask(), createSnapshot());
+        assertNotNull(snapshotCache.getSnapshot(window.getTask()));
+        snapshotCache.cleanCache(window.mAppToken);
+        assertNull(snapshotCache.getSnapshot(window.getTask()));
+    }
+
+    private TaskSnapshot createSnapshot() {
+        GraphicBuffer buffer = create(1, 1, PixelFormat.RGBA_8888,
+                USAGE_HW_TEXTURE | USAGE_SW_WRITE_NEVER | USAGE_SW_READ_NEVER);
+        return new TaskSnapshot(buffer, Configuration.ORIENTATION_PORTRAIT, new Rect());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
index 24893a1..bb9bc9e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskStackContainersTests.java
@@ -17,13 +17,17 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import android.hardware.display.DisplayManagerGlobal;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
+import android.view.DisplayInfo;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -88,6 +92,33 @@
         assertEquals(taskStackContainer.mChildren.get(pinnedStackPos), pinnedStack);
     }
 
+    @Test
+    public void testReparentBetweenDisplays() throws Exception {
+        // Create first stack on primary display.
+        final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
+        final TestTaskWindowContainerController taskController =
+                new TestTaskWindowContainerController(stack1.mStackId);
+        final TestTask task1 = (TestTask) taskController.mContainer;
+        task1.mOnDisplayChangedCalled = false;
+
+        // Create second display and put second stack on it.
+        final Display display = new Display(DisplayManagerGlobal.getInstance(),
+                sDisplayContent.getDisplayId() + 1, new DisplayInfo(),
+                DEFAULT_DISPLAY_ADJUSTMENTS);
+        final DisplayContent dc = new DisplayContent(display, sWm, sLayersController,
+                new WallpaperController(sWm));
+        sWm.mRoot.addChild(dc, 1);
+        final TaskStack stack2 = createTaskStackOnDisplay(dc);
+
+        // Reparent and check state.DisplayContent.java:2572
+        sWm.moveStackToDisplay(stack1.mStackId, dc.getDisplayId());
+        assertEquals(dc, stack1.getDisplayContent());
+        final int stack1PositionInParent = stack1.getParent().mChildren.indexOf(stack1);
+        final int stack2PositionInParent = stack1.getParent().mChildren.indexOf(stack2);
+        assertEquals(stack1PositionInParent, stack2PositionInParent + 1);
+        assertTrue(task1.mOnDisplayChangedCalled);
+    }
+
     private TaskStack addPinnedStack() {
         TaskStack pinnedStack = sWm.mStackIdToStack.get(PINNED_STACK_ID);
         if (pinnedStack == null) {
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
index 0dd31c3..7cd3f64 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskWindowContainerControllerTests.java
@@ -16,11 +16,21 @@
 
 package com.android.server.wm;
 
+import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS;
+
 import org.junit.Test;
 
+import android.hardware.display.DisplayManagerGlobal;
 import android.platform.test.annotations.Presubmit;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.view.Display;
+import android.view.DisplayInfo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
 /**
  * Test class for {@link TaskWindowContainerController}.
@@ -32,7 +42,102 @@
 @Presubmit
 @org.junit.runner.RunWith(AndroidJUnit4.class)
 public class TaskWindowContainerControllerTests extends WindowTestsBase {
-// TODO Add tests once StackWindowContainerController is created.
+
     @Test
-    public void dummyTest() throws Exception {}
+    public void testRemoveContainer() throws Exception {
+        final TestTaskWindowContainerController taskController =
+                new TestTaskWindowContainerController();
+        final TestAppWindowContainerController appController =
+                new TestAppWindowContainerController(taskController);
+
+        taskController.removeContainer();
+        // Assert that the container was removed.
+        assertNull(taskController.mContainer);
+        assertNull(appController.mContainer);
+    }
+
+    @Test
+    public void testRemoveContainer_DeferRemoval() throws Exception {
+        final TestTaskWindowContainerController taskController =
+                new TestTaskWindowContainerController();
+        final TestAppWindowContainerController appController =
+                new TestAppWindowContainerController(taskController);
+
+        final TestTask task = (TestTask) taskController.mContainer;
+        final AppWindowToken app = appController.mContainer;
+        task.mShouldDeferRemoval = true;
+
+        taskController.removeContainer();
+        // For the case of deferred removal the task controller will no longer be connected to the
+        // container, but the app controller will still be connected to the its container until
+        // the task window container is removed.
+        assertNull(taskController.mContainer);
+        assertNull(task.getController());
+        assertNotNull(appController.mContainer);
+        assertNotNull(app.getController());
+
+        task.removeImmediately();
+        assertNull(appController.mContainer);
+        assertNull(app.getController());
+    }
+
+    @Test
+    public void testReparent() throws Exception {
+        final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
+        final TestTaskWindowContainerController taskController =
+                new TestTaskWindowContainerController(stack1.mStackId);
+        final TaskStack stack2 = createTaskStackOnDisplay(sDisplayContent);
+        final TestTaskWindowContainerController taskController2 =
+                new TestTaskWindowContainerController(stack2.mStackId);
+
+        boolean gotException = false;
+        try {
+            taskController.reparent(stack1.mStackId, 0);
+        } catch (IllegalArgumentException e) {
+            gotException = true;
+        }
+        assertTrue("Should not be able to reparent to the same parent", gotException);
+
+        gotException = false;
+        try {
+            taskController.reparent(sNextStackId + 1, 0);
+        } catch (IllegalArgumentException e) {
+            gotException = true;
+        }
+        assertTrue("Should not be able to reparent to a stackId that doesn't exist", gotException);
+
+        taskController.reparent(stack2.mStackId, 0);
+        assertEquals(stack2, taskController.mContainer.getParent());
+        assertEquals(0, ((TestTask) taskController.mContainer).positionInParent());
+        assertEquals(1, ((TestTask) taskController2.mContainer).positionInParent());
+    }
+
+    @Test
+    public void testReparentBetweenDisplays() throws Exception {
+        // Create first stack on primary display.
+        final TaskStack stack1 = createTaskStackOnDisplay(sDisplayContent);
+        final TestTaskWindowContainerController taskController =
+                new TestTaskWindowContainerController(stack1.mStackId);
+        final TestTask task1 = (TestTask) taskController.mContainer;
+        task1.mOnDisplayChangedCalled = false;
+
+        // Create second display and put second stack on it.
+        final Display display = new Display(DisplayManagerGlobal.getInstance(),
+                sDisplayContent.getDisplayId() + 1, new DisplayInfo(),
+                DEFAULT_DISPLAY_ADJUSTMENTS);
+        final DisplayContent dc = new DisplayContent(display, sWm, sLayersController,
+                new WallpaperController(sWm));
+        sWm.mRoot.addChild(dc, 1);
+        final TaskStack stack2 = createTaskStackOnDisplay(dc);
+        final TestTaskWindowContainerController taskController2 =
+                new TestTaskWindowContainerController(stack2.mStackId);
+        final TestTask task2 = (TestTask) taskController2.mContainer;
+
+        // Reparent and check state
+        taskController.reparent(stack2.mStackId, 0);
+        assertEquals(stack2, task1.getParent());
+        assertEquals(0, task1.positionInParent());
+        assertEquals(1, task2.positionInParent());
+        assertTrue(task1.mOnDisplayChangedCalled);
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 12e7a15..c0c8fb0 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -65,6 +65,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.hardware.display.DisplayManagerInternal;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -75,10 +76,12 @@
 import android.view.WindowManager;
 import android.view.WindowManagerPolicy;
 import android.view.animation.Animation;
+import android.os.PowerManagerInternal;
 
 import com.android.internal.policy.IKeyguardDismissCallback;
 import com.android.internal.policy.IShortcutService;
 import com.android.server.input.InputManagerService;
+import com.android.server.LocalServices;
 
 import java.io.PrintWriter;
 
@@ -87,10 +90,20 @@
 
     private static WindowManagerService sWm = null;
 
+    int rotationToReport = 0;
+
     static synchronized WindowManagerService getWindowManagerService(Context context) {
         if (sWm == null) {
             // We only want to do this once for the test process as we don't want WM to try to
             // register a bunch of local services again.
+            if (LocalServices.getService(DisplayManagerInternal.class) == null) {
+                LocalServices.addService(DisplayManagerInternal.class,
+                        mock(DisplayManagerInternal.class));
+            }
+            if (LocalServices.getService(PowerManagerInternal.class) == null) {
+                LocalServices.addService(PowerManagerInternal.class,
+                        mock(PowerManagerInternal.class));
+            }
             sWm = WindowManagerService.main(context, mock(InputManagerService.class), true, false,
                     false, new TestWindowManagerPolicy());
         }
@@ -543,7 +556,7 @@
     @Override
     public int rotationForOrientationLw(int orientation,
             int lastRotation) {
-        return 0;
+        return rotationToReport;
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
index b57329c..4f740ac 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowContainerTests.java
@@ -315,7 +315,7 @@
         gotException = false;
         try {
             // Check response to position that's bigger than child number.
-            root.positionChildAt(2, child1, false /* includingParents */);
+            root.positionChildAt(3, child1, false /* includingParents */);
         } catch (IllegalArgumentException e) {
             gotException = true;
         }
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
index 466bd67..813d263 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowTestsBase.java
@@ -16,9 +16,15 @@
 
 package com.android.server.wm;
 
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
+import android.view.IApplicationToken;
 import org.junit.Assert;
 import org.junit.Before;
 
+import android.app.ActivityManager;
+import android.app.ActivityManager.TaskSnapshot;
 import android.content.Context;
 import android.os.IBinder;
 import android.support.test.InstrumentationRegistry;
@@ -28,6 +34,7 @@
 import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
 import static android.app.AppOpsManager.OP_NONE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.content.res.Configuration.EMPTY;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
@@ -50,7 +57,7 @@
     static WindowManagerService sWm = null;
     private final IWindow mIWindow = new TestIWindow();
     private final Session mMockSession = mock(Session.class);
-    private static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
+    static int sNextStackId = FIRST_DYNAMIC_STACK_ID;
     private static int sNextTaskId = 0;
 
     private static boolean sOneTimeSetupDone = false;
@@ -177,7 +184,7 @@
         }
     }
 
-    /* Used so we can gain access to some protected members of the {@link AppWindowToken} class */
+    /** Used so we can gain access to some protected members of the {@link AppWindowToken} class. */
     class TestAppWindowToken extends AppWindowToken {
 
         TestAppWindowToken(DisplayContent dc) {
@@ -201,16 +208,117 @@
         }
     }
 
+    /* Used so we can gain access to some protected members of the {@link Task} class */
+    class TestTask extends Task {
+
+        boolean mShouldDeferRemoval = false;
+        boolean mOnDisplayChangedCalled = false;
+
+        TestTask(int taskId, TaskStack stack, int userId, WindowManagerService service, Rect bounds,
+                Configuration overrideConfig, boolean isOnTopLauncher, int resizeMode,
+                boolean homeTask, TaskWindowContainerController controller) {
+            super(taskId, stack, userId, service, bounds, overrideConfig, isOnTopLauncher,
+                    resizeMode, homeTask, controller);
+        }
+
+        boolean shouldDeferRemoval() {
+            return mShouldDeferRemoval;
+        }
+
+        int positionInParent() {
+            return getParent().mChildren.indexOf(this);
+        }
+
+        @Override
+        void onDisplayChanged(DisplayContent dc) {
+            super.onDisplayChanged(dc);
+            mOnDisplayChangedCalled = true;
+        }
+    }
+
     /**
      * Used so we can gain access to some protected members of {@link TaskWindowContainerController}
      * class.
      */
     class TestTaskWindowContainerController extends TaskWindowContainerController {
 
+        TestTaskWindowContainerController() {
+            this(createTaskStackOnDisplay(sDisplayContent).mStackId);
+        }
+
         TestTaskWindowContainerController(int stackId) {
-            super(sNextTaskId++, stackId, 0 /* userId */, null /* bounds */,
+            super(sNextTaskId++, snapshot -> {}, stackId, 0 /* userId */, null /* bounds */,
                     EMPTY /* overrideConfig*/, RESIZE_MODE_UNRESIZEABLE, false /* homeTask*/,
                     false /* isOnTopLauncher */, true /* toTop*/, true /* showForAllUsers */);
         }
+
+        @Override
+        TestTask createTask(int taskId, TaskStack stack, int userId, Rect bounds,
+                Configuration overrideConfig, int resizeMode, boolean homeTask,
+                boolean isOnTopLauncher) {
+            return new TestTask(taskId, stack, userId, mService, bounds, overrideConfig,
+                    isOnTopLauncher, resizeMode, homeTask, this);
+        }
+    }
+
+    class TestAppWindowContainerController extends AppWindowContainerController {
+
+        final IApplicationToken mToken;
+
+        TestAppWindowContainerController(TestTaskWindowContainerController taskController) {
+            this(taskController, new TestIApplicationToken());
+        }
+
+        TestAppWindowContainerController(TestTaskWindowContainerController taskController,
+                IApplicationToken token) {
+            super(taskController, token, null /* listener */, 0 /* index */,
+                    SCREEN_ORIENTATION_UNSPECIFIED, true /* fullscreen */,
+                    true /* showForAllUsers */, 0 /* configChanges */, false /* voiceInteraction */,
+                    false /* launchTaskBehind */, false /* alwaysFocusable */,
+                    0 /* targetSdkVersion */, 0 /* rotationAnimationHint */,
+                    0 /* inputDispatchingTimeoutNanos */, sWm);
+            mToken = token;
+        }
+    }
+
+    class TestIApplicationToken implements IApplicationToken {
+
+        private final Binder mBinder = new Binder();
+        @Override
+        public IBinder asBinder() {
+            return mBinder;
+        }
+    }
+
+    /** Used to track resize reports. */
+    class TestWindowState extends WindowState {
+        boolean resizeReported;
+
+        TestWindowState(WindowManager.LayoutParams attrs, WindowToken token) {
+            super(sWm, mMockSession, mIWindow, token, null, OP_NONE, 0, attrs, 0, 0);
+        }
+
+        @Override
+        void reportResized() {
+            super.reportResized();
+            resizeReported = true;
+        }
+
+        @Override
+        public boolean isGoneForLayoutLw() {
+            return false;
+        }
+
+        @Override
+        void updateResizingWindowIfNeeded() {
+            // Used in AppWindowTokenTests#testLandscapeSeascapeRotationRelayout to deceive
+            // the system that it can actually update the window.
+            boolean hadSurface = mHasSurface;
+            mHasSurface = true;
+
+            super.updateResizingWindowIfNeeded();
+
+            mHasSurface = hadSurface;
+        }
     }
 }
diff --git a/services/usage/java/com/android/server/usage/StorageStatsService.java b/services/usage/java/com/android/server/usage/StorageStatsService.java
index 3be04d4..68765b6 100644
--- a/services/usage/java/com/android/server/usage/StorageStatsService.java
+++ b/services/usage/java/com/android/server/usage/StorageStatsService.java
@@ -31,9 +31,10 @@
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.os.storage.StorageEventListener;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
-import android.util.Log;
+import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.server.SystemService;
@@ -66,6 +67,7 @@
     private final UserManager mUser;
     private final PackageManager mPackage;
     private final StorageManager mStorage;
+
     private final Installer mInstaller;
 
     public StorageStatsService(Context context) {
@@ -74,8 +76,28 @@
         mUser = context.getSystemService(UserManager.class);
         mPackage = context.getSystemService(PackageManager.class);
         mStorage = context.getSystemService(StorageManager.class);
+
         mInstaller = new Installer(context);
         mInstaller.onStart();
+        invalidateMounts();
+
+        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();
+                }
+            }
+        });
+    }
+
+    private void invalidateMounts() {
+        try {
+            mInstaller.invalidateMounts();
+        } catch (InstallerException e) {
+            Slog.wtf(TAG, "Failed to invalidate mounts", e);
+        }
     }
 
     private void enforcePermission(int callingUid, String callingPackage) {
@@ -242,7 +264,7 @@
 
     private static void checkEquals(String msg, long expected, long actual) {
         if (expected != actual) {
-            Log.e(TAG, msg + " expected " + expected + " actual " + actual);
+            Slog.e(TAG, msg + " expected " + expected + " actual " + actual);
         }
     }
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 4bfc3df..d243bf2 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -20,6 +20,7 @@
 import android.app.ActivityManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.IUidObserver;
 import android.app.admin.DevicePolicyManager;
 import android.app.usage.ConfigurationStats;
 import android.app.usage.IUsageStatsManager;
@@ -38,9 +39,9 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.UserInfo;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.hardware.display.DisplayManager;
@@ -49,6 +50,7 @@
 import android.os.BatteryStats;
 import android.os.Binder;
 import android.os.Environment;
+import android.os.FileUtils;
 import android.os.Handler;
 import android.os.IDeviceIdleController;
 import android.os.Looper;
@@ -80,6 +82,7 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -103,6 +106,8 @@
     private static final long FLUSH_INTERVAL = COMPRESS_TIME ? TEN_SECONDS : TWENTY_MINUTES;
     private static final long TIME_CHANGE_THRESHOLD_MILLIS = 2 * 1000; // Two seconds.
 
+    private static final File KERNEL_COUNTER_FILE = new File("/proc/uid_procstat/set");
+
     long mAppIdleScreenThresholdMillis;
     long mCheckIdleIntervalMillis;
     long mAppIdleWallclockThresholdMillis;
@@ -134,6 +139,7 @@
     private IBatteryStats mBatteryStats;
 
     private final SparseArray<UserUsageStatsService> mUserState = new SparseArray<>();
+    private final SparseIntArray mUidToKernelCounter = new SparseIntArray();
     private File mUsageStatsDir;
     long mRealTimeSnapshot;
     long mSystemTimeSnapshot;
@@ -235,6 +241,19 @@
                 postOneTimeCheckIdleStates();
             }
 
+            if (KERNEL_COUNTER_FILE.exists()) {
+                try {
+                    ActivityManager.getService().registerUidObserver(mUidObserver,
+                            ActivityManager.UID_OBSERVER_PROCSTATE
+                                    | ActivityManager.UID_OBSERVER_GONE,
+                            ActivityManager.PROCESS_STATE_UNKNOWN, null);
+                } catch (RemoteException e) {
+                    throw new RuntimeException(e);
+                }
+            } else {
+                Slog.w(TAG, "Missing procfs interface: " + KERNEL_COUNTER_FILE);
+            }
+
             mSystemServicesReady = true;
         } else if (phase == PHASE_BOOT_COMPLETED) {
             setChargingState(getContext().getSystemService(BatteryManager.class).isCharging());
@@ -311,6 +330,39 @@
         }
     };
 
+    private final IUidObserver mUidObserver = new IUidObserver.Stub() {
+        @Override
+        public void onUidStateChanged(int uid, int procState) {
+            final int newCounter = (procState <= ActivityManager.PROCESS_STATE_TOP) ? 0 : 1;
+            synchronized (mUidToKernelCounter) {
+                final int oldCounter = mUidToKernelCounter.get(uid, 0);
+                if (newCounter != oldCounter) {
+                    mUidToKernelCounter.put(uid, newCounter);
+                    try {
+                        FileUtils.stringToFile(KERNEL_COUNTER_FILE, uid + " " + newCounter);
+                    } catch (IOException e) {
+                        Slog.w(TAG, "Failed to update counter set: " + e);
+                    }
+                }
+            }
+        }
+
+        @Override
+        public void onUidIdle(int uid, boolean disabled) throws RemoteException {
+            // Ignored
+        }
+
+        @Override
+        public void onUidGone(int uid, boolean disabled) throws RemoteException {
+            onUidStateChanged(uid, ActivityManager.PROCESS_STATE_NONEXISTENT);
+        }
+
+        @Override
+        public void onUidActive(int uid) throws RemoteException {
+            // Ignored
+        }
+    };
+
     @Override
     public void onStatsUpdated() {
         mHandler.sendEmptyMessageDelayed(MSG_FLUSH_TO_DISK, FLUSH_INTERVAL);
diff --git a/test-runner/Android.mk b/test-runner/Android.mk
index 0e9a485..3c36e42 100644
--- a/test-runner/Android.mk
+++ b/test-runner/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_JAVA_LIBRARIES := core-oj core-libart junit framework
+LOCAL_JAVA_LIBRARIES := core-oj core-libart framework legacy-test
 
 LOCAL_MODULE:= android.test.runner
 
diff --git a/test-runner/tests/Android.mk b/test-runner/tests/Android.mk
index d1efe7b..68fd662 100644
--- a/test-runner/tests/Android.mk
+++ b/test-runner/tests/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/AppLaunch/Android.mk b/tests/AppLaunch/Android.mk
index e6f6c39..9435893 100644
--- a/tests/AppLaunch/Android.mk
+++ b/tests/AppLaunch/Android.mk
@@ -11,7 +11,7 @@
 LOCAL_CERTIFICATE := platform
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test legacy-android-test
 
 include $(BUILD_PACKAGE)
 
diff --git a/tests/BrowserPowerTest/Android.mk b/tests/BrowserPowerTest/Android.mk
index f2c07b3..59bc729 100644
--- a/tests/BrowserPowerTest/Android.mk
+++ b/tests/BrowserPowerTest/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 # Include all test java files.
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
index 50926a6..1f14f03 100644
--- a/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
+++ b/tests/Camera2Tests/SmartCamera/SimpleCamera/tests/Android.mk
@@ -25,13 +25,8 @@
 LOCAL_SRC_FILES += $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
-#LOCAL_STATIC_JAVA_LIBRARIES := filterframework-test-lib
-LOCAL_STATIC_JAVA_LIBRARIES += guava
+LOCAL_STATIC_JAVA_LIBRARIES := guava junit legacy-android-test
 
-#LOCAL_JAVA_LIBRARIES := filterframework-test-lib
-LOCAL_STATIC_JAVA_LIBRARIES := guava
-
-LOCAL_STATIC_JAVA_LIBRARIES +=
 LOCAL_PROGUARD_ENABLED := disabled
 
 LOCAL_INSTRUMENTATION_FOR := SmartCamera
diff --git a/tests/CanvasCompare/Android.mk b/tests/CanvasCompare/Android.mk
index 642c9e9..90de503 100644
--- a/tests/CanvasCompare/Android.mk
+++ b/tests/CanvasCompare/Android.mk
@@ -24,5 +24,6 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 include $(BUILD_PACKAGE)
diff --git a/tests/Compatibility/Android.mk b/tests/Compatibility/Android.mk
index c2f89dd..99e84bd 100644
--- a/tests/Compatibility/Android.mk
+++ b/tests/Compatibility/Android.mk
@@ -19,6 +19,7 @@
 LOCAL_MODULE_TAGS := tests
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 # Include all test java files.
 LOCAL_SRC_FILES := \
 	$(call all-java-files-under, src)
diff --git a/tests/CoreTests/android/Android.mk b/tests/CoreTests/android/Android.mk
index 5f3d0d9..c9f1161 100644
--- a/tests/CoreTests/android/Android.mk
+++ b/tests/CoreTests/android/Android.mk
@@ -7,6 +7,7 @@
 	$(call all-subdir-java-files)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle conscrypt org.apache.http.legacy
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 LOCAL_PACKAGE_NAME := CoreTests
 
diff --git a/tests/DataIdleTest/Android.mk b/tests/DataIdleTest/Android.mk
index acb46c5..4e15729 100644
--- a/tests/DataIdleTest/Android.mk
+++ b/tests/DataIdleTest/Android.mk
@@ -21,6 +21,7 @@
 
 LOCAL_PACKAGE_NAME := DataIdleTest
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 # We need to sign it to get access to the network usage history.
diff --git a/tests/FrameworkPerf/Android.mk b/tests/FrameworkPerf/Android.mk
index 2eb52f0..d2ec753 100644
--- a/tests/FrameworkPerf/Android.mk
+++ b/tests/FrameworkPerf/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_PACKAGE_NAME := FrameworkPerf
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 LOCAL_AAPT_FLAGS = -c 120dpi,240dpi,160dpi,161dpi,320dpi,nodpi
 
diff --git a/tests/HierarchyViewerTest/Android.mk b/tests/HierarchyViewerTest/Android.mk
index 07b90f0..f8c8656 100644
--- a/tests/HierarchyViewerTest/Android.mk
+++ b/tests/HierarchyViewerTest/Android.mk
@@ -8,5 +8,6 @@
 LOCAL_PACKAGE_NAME := HierarchyViewerTest
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 include $(BUILD_PACKAGE)
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
index 0f1924c..6042471 100644
--- a/tests/ImfTest/tests/Android.mk
+++ b/tests/ImfTest/tests/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 LOCAL_PACKAGE_NAME := ImfTestTests
 
diff --git a/tests/MemoryUsage/Android.mk b/tests/MemoryUsage/Android.mk
index 0ab793b..578e628 100644
--- a/tests/MemoryUsage/Android.mk
+++ b/tests/MemoryUsage/Android.mk
@@ -10,8 +10,9 @@
 
 LOCAL_CERTIFICATE := platform
 LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 
 include $(BUILD_PACKAGE)
 
 # Use the following include to make our test apk.
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/NetworkSecurityConfigTest/Android.mk b/tests/NetworkSecurityConfigTest/Android.mk
index a63162d..dd9ff11 100644
--- a/tests/NetworkSecurityConfigTest/Android.mk
+++ b/tests/NetworkSecurityConfigTest/Android.mk
@@ -6,6 +6,7 @@
 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)
diff --git a/tests/SoundTriggerTests/Android.mk b/tests/SoundTriggerTests/Android.mk
index e67134d..359484e 100644
--- a/tests/SoundTriggerTests/Android.mk
+++ b/tests/SoundTriggerTests/Android.mk
@@ -27,7 +27,7 @@
   LOCAL_SRC_FILES := src/android/hardware/soundtrigger/SoundTriggerTest.java
 endif
 
-LOCAL_STATIC_JAVA_LIBRARIES := mockito-target
+LOCAL_STATIC_JAVA_LIBRARIES := mockito-target legacy-android-test
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_PACKAGE_NAME := SoundTriggerTests
diff --git a/tests/TtsTests/Android.mk b/tests/TtsTests/Android.mk
index e049c90..ed63e12 100644
--- a/tests/TtsTests/Android.mk
+++ b/tests/TtsTests/Android.mk
@@ -20,7 +20,7 @@
 
 LOCAL_SRC_FILES := $(call all-subdir-java-files)
 
-LOCAL_STATIC_JAVA_LIBRARIES := littlemock
+LOCAL_STATIC_JAVA_LIBRARIES := littlemock junit legacy-android-test
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
 LOCAL_PACKAGE_NAME := TtsTests
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index b2a9a49..00420e9 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -16,6 +16,8 @@
 
 package com.android.server.connectivity.tethering;
 
+import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
+import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -114,6 +116,9 @@
         mUNM.registerMobileNetworkRequest();
         assertTrue(mUNM.mobileNetworkRequested());
         assertEquals(1, mCM.requested.size());
+        assertEquals(1, mCM.legacyTypeMap.size());
+        assertEquals(Integer.valueOf(TYPE_MOBILE_HIPRI),
+                mCM.legacyTypeMap.values().iterator().next());
         assertFalse(mCM.isDunRequested());
 
         mUNM.stop();
@@ -137,6 +142,9 @@
         mUNM.registerMobileNetworkRequest();
         assertTrue(mUNM.mobileNetworkRequested());
         assertEquals(1, mCM.requested.size());
+        assertEquals(1, mCM.legacyTypeMap.size());
+        assertEquals(Integer.valueOf(TYPE_MOBILE_DUN),
+                mCM.legacyTypeMap.values().iterator().next());
         assertTrue(mCM.isDunRequested());
 
         mUNM.stop();
@@ -148,6 +156,7 @@
         public Set<NetworkCallback> trackingDefault = new HashSet<>();
         public Map<NetworkCallback, NetworkRequest> listening = new HashMap<>();
         public Map<NetworkCallback, NetworkRequest> requested = new HashMap<>();
+        public Map<NetworkCallback, Integer> legacyTypeMap = new HashMap<>();
 
         public TestConnectivityManager(Context ctx, IConnectivityManager svc) {
             super(ctx, svc);
@@ -156,7 +165,8 @@
         boolean isEmpty() {
             return trackingDefault.isEmpty() &&
                    listening.isEmpty() &&
-                   requested.isEmpty();
+                   requested.isEmpty() &&
+                   legacyTypeMap.isEmpty();
         }
 
         boolean isListeningForDun() {
@@ -184,6 +194,17 @@
         }
 
         @Override
+        public void requestNetwork(NetworkRequest req, NetworkCallback cb,
+                int timeoutMs, int legacyType) {
+            assertFalse(requested.containsKey(cb));
+            requested.put(cb, req);
+            assertFalse(legacyTypeMap.containsKey(cb));
+            if (legacyType != ConnectivityManager.TYPE_NONE) {
+                legacyTypeMap.put(cb, legacyType);
+            }
+        }
+
+        @Override
         public void registerNetworkCallback(NetworkRequest req, NetworkCallback cb) {
             assertFalse(listening.containsKey(cb));
             listening.put(cb, req);
@@ -203,6 +224,7 @@
                 listening.remove(cb);
             } else if (requested.containsKey(cb)) {
                 requested.remove(cb);
+                legacyTypeMap.remove(cb);
             }
 
             assertFalse(trackingDefault.contains(cb));
diff --git a/tests/permission/Android.mk b/tests/permission/Android.mk
index 31a0daf..54688c8 100644
--- a/tests/permission/Android.mk
+++ b/tests/permission/Android.mk
@@ -8,6 +8,7 @@
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
 LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
+LOCAL_STATIC_JAVA_LIBRARIES := junit legacy-android-test
 LOCAL_PACKAGE_NAME := FrameworkPermissionTests
 
 include $(BUILD_PACKAGE)
diff --git a/tests/utils/testutils/Android.mk b/tests/utils/testutils/Android.mk
index 392d398..43d1e37 100644
--- a/tests/utils/testutils/Android.mk
+++ b/tests/utils/testutils/Android.mk
@@ -25,6 +25,7 @@
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
     android-support-test \
+    legacy-android-test \
     mockito-target-minus-junit4
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/tools/aapt2/Android.bp b/tools/aapt2/Android.bp
new file mode 100644
index 0000000..20439cc
--- /dev/null
+++ b/tools/aapt2/Android.bp
@@ -0,0 +1,170 @@
+//
+// Copyright (C) 2015 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.
+//
+
+toolSources = [
+    "compile/Compile.cpp",
+    "diff/Diff.cpp",
+    "dump/Dump.cpp",
+    "link/Link.cpp",
+]
+
+cc_defaults {
+    name: "aapt_defaults",
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wno-unused-parameter",
+    ],
+    cppflags: [
+        "-Wno-missing-field-initializers",
+        "-fno-exceptions",
+        "-fno-rtti",
+    ],
+    target: {
+        windows: {
+            enabled: true,
+            cflags: ["-Wno-maybe-uninitialized"],
+            static_libs: ["libz"],
+        },
+        darwin: {
+            cflags: ["-D_DARWIN_UNLIMITED_STREAMS"],
+            host_ldlibs: ["-lz"],
+        },
+        linux: {
+            host_ldlibs: ["-lz"],
+        },
+    },
+    static_libs: [
+        "libandroidfw",
+        "libutils",
+        "liblog",
+        "libcutils",
+        "libexpat",
+        "libziparchive",
+        "libpng",
+        "libbase",
+        "libprotobuf-cpp-lite",
+    ],
+    group_static_libs: true,
+}
+
+// ==========================================================
+// NOTE: Do not add any shared libraries.
+// AAPT2 is built to run on many environments
+// that may not have the required dependencies.
+// ==========================================================
+
+// ==========================================================
+// Build the host static library: aapt2
+// ==========================================================
+cc_library_host_static {
+    name: "libaapt2",
+    srcs: [
+        "compile/IdAssigner.cpp",
+        "compile/InlineXmlFormatParser.cpp",
+        "compile/NinePatch.cpp",
+        "compile/Png.cpp",
+        "compile/PngChunkFilter.cpp",
+        "compile/PngCrunch.cpp",
+        "compile/PseudolocaleGenerator.cpp",
+        "compile/Pseudolocalizer.cpp",
+        "compile/XmlIdCollector.cpp",
+        "filter/ConfigFilter.cpp",
+        "flatten/Archive.cpp",
+        "flatten/TableFlattener.cpp",
+        "flatten/XmlFlattener.cpp",
+        "io/File.cpp",
+        "io/FileSystem.cpp",
+        "io/Io.cpp",
+        "io/ZipArchive.cpp",
+        "link/AutoVersioner.cpp",
+        "link/ManifestFixer.cpp",
+        "link/ProductFilter.cpp",
+        "link/PrivateAttributeMover.cpp",
+        "link/ReferenceLinker.cpp",
+        "link/ResourceDeduper.cpp",
+        "link/TableMerger.cpp",
+        "link/VersionCollapser.cpp",
+        "link/XmlNamespaceRemover.cpp",
+        "link/XmlReferenceLinker.cpp",
+        "process/SymbolTable.cpp",
+        "proto/ProtoHelpers.cpp",
+        "proto/TableProtoDeserializer.cpp",
+        "proto/TableProtoSerializer.cpp",
+        "split/TableSplitter.cpp",
+        "unflatten/BinaryResourceParser.cpp",
+        "unflatten/ResChunkPullParser.cpp",
+        "util/BigBuffer.cpp",
+        "util/Files.cpp",
+        "util/Util.cpp",
+        "ConfigDescription.cpp",
+        "Debug.cpp",
+        "DominatorTree.cpp",
+        "Flags.cpp",
+        "java/AnnotationProcessor.cpp",
+        "java/ClassDefinition.cpp",
+        "java/JavaClassGenerator.cpp",
+        "java/ManifestClassGenerator.cpp",
+        "java/ProguardRules.cpp",
+        "Locale.cpp",
+        "Resource.cpp",
+        "ResourceParser.cpp",
+        "ResourceTable.cpp",
+        "ResourceUtils.cpp",
+        "ResourceValues.cpp",
+        "SdkConstants.cpp",
+        "StringPool.cpp",
+        "xml/XmlActionExecutor.cpp",
+        "xml/XmlDom.cpp",
+        "xml/XmlPullParser.cpp",
+        "xml/XmlUtil.cpp",
+        "Format.proto",
+    ],
+    proto: {
+        export_proto_headers: true,
+    },
+    defaults: ["aapt_defaults"],
+}
+
+// ==========================================================
+// Build the host shared library: aapt2_jni
+// ==========================================================
+cc_library_host_shared {
+    name: "libaapt2_jni",
+    srcs: toolSources + ["jni/aapt2_jni.cpp"],
+    static_libs: ["libaapt2"],
+    defaults: ["aapt_defaults"],
+}
+
+// ==========================================================
+// Build the host tests: aapt2_tests
+// ==========================================================
+cc_test_host {
+    name: "aapt2_tests",
+    srcs: ["**/*_test.cpp"],
+    static_libs: ["libaapt2"],
+    defaults: ["aapt_defaults"],
+}
+
+// ==========================================================
+// Build the host executable: aapt2
+// ==========================================================
+cc_binary_host {
+    name: "aapt2",
+    srcs: ["Main.cpp"] + toolSources,
+    static_libs: ["libaapt2"],
+    defaults: ["aapt_defaults"],
+}
diff --git a/tools/aapt2/Android.mk b/tools/aapt2/Android.mk
deleted file mode 100644
index 1efd2ed..0000000
--- a/tools/aapt2/Android.mk
+++ /dev/null
@@ -1,253 +0,0 @@
-#
-# Copyright (C) 2015 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.
-#
-LOCAL_PATH:= $(call my-dir)
-
-# ==========================================================
-# Setup some common variables for the different build
-# targets here.
-# ==========================================================
-
-main := Main.cpp
-sources := \
-	compile/IdAssigner.cpp \
-	compile/InlineXmlFormatParser.cpp \
-	compile/NinePatch.cpp \
-	compile/Png.cpp \
-	compile/PngChunkFilter.cpp \
-	compile/PngCrunch.cpp \
-	compile/PseudolocaleGenerator.cpp \
-	compile/Pseudolocalizer.cpp \
-	compile/XmlIdCollector.cpp \
-	filter/ConfigFilter.cpp \
-	flatten/Archive.cpp \
-	flatten/TableFlattener.cpp \
-	flatten/XmlFlattener.cpp \
-	io/File.cpp \
-	io/FileSystem.cpp \
-	io/Io.cpp \
-	io/ZipArchive.cpp \
-	link/AutoVersioner.cpp \
-	link/ManifestFixer.cpp \
-	link/ProductFilter.cpp \
-	link/PrivateAttributeMover.cpp \
-	link/ReferenceLinker.cpp \
-	link/ResourceDeduper.cpp \
-	link/TableMerger.cpp \
-	link/VersionCollapser.cpp \
-	link/XmlNamespaceRemover.cpp \
-	link/XmlReferenceLinker.cpp \
-	process/SymbolTable.cpp \
-	proto/ProtoHelpers.cpp \
-	proto/TableProtoDeserializer.cpp \
-	proto/TableProtoSerializer.cpp \
-	split/TableSplitter.cpp \
-	unflatten/BinaryResourceParser.cpp \
-	unflatten/ResChunkPullParser.cpp \
-	util/BigBuffer.cpp \
-	util/Files.cpp \
-	util/Util.cpp \
-	ConfigDescription.cpp \
-	Debug.cpp \
-	DominatorTree.cpp \
-	Flags.cpp \
-	java/AnnotationProcessor.cpp \
-	java/ClassDefinition.cpp \
-	java/JavaClassGenerator.cpp \
-	java/ManifestClassGenerator.cpp \
-	java/ProguardRules.cpp \
-	Locale.cpp \
-	Resource.cpp \
-	ResourceParser.cpp \
-	ResourceTable.cpp \
-	ResourceUtils.cpp \
-	ResourceValues.cpp \
-	SdkConstants.cpp \
-	StringPool.cpp \
-	xml/XmlActionExecutor.cpp \
-	xml/XmlDom.cpp \
-	xml/XmlPullParser.cpp \
-	xml/XmlUtil.cpp
-
-sources += Format.proto
-
-sourcesJni := jni/aapt2_jni.cpp
-
-testSources := \
-	compile/IdAssigner_test.cpp \
-	compile/InlineXmlFormatParser_test.cpp \
-	compile/NinePatch_test.cpp \
-	compile/PseudolocaleGenerator_test.cpp \
-	compile/Pseudolocalizer_test.cpp \
-	compile/XmlIdCollector_test.cpp \
-	filter/ConfigFilter_test.cpp \
-	flatten/TableFlattener_test.cpp \
-	flatten/XmlFlattener_test.cpp \
-	link/AutoVersioner_test.cpp \
-	link/ManifestFixer_test.cpp \
-	link/PrivateAttributeMover_test.cpp \
-	link/ProductFilter_test.cpp \
-	link/ReferenceLinker_test.cpp \
-	link/ResourceDeduper_test.cpp \
-	link/TableMerger_test.cpp \
-	link/VersionCollapser_test.cpp \
-	link/XmlNamespaceRemover_test.cpp \
-	link/XmlReferenceLinker_test.cpp \
-	process/SymbolTable_test.cpp \
-	proto/TableProtoSerializer_test.cpp \
-	split/TableSplitter_test.cpp \
-	util/BigBuffer_test.cpp \
-	util/Files_test.cpp \
-	util/Maybe_test.cpp \
-	util/StringPiece_test.cpp \
-	util/Util_test.cpp \
-	ConfigDescription_test.cpp \
-	DominatorTree_test.cpp \
-	java/AnnotationProcessor_test.cpp \
-	java/JavaClassGenerator_test.cpp \
-	java/ManifestClassGenerator_test.cpp \
-	Locale_test.cpp \
-	NameMangler_test.cpp \
-	Resource_test.cpp \
-	ResourceParser_test.cpp \
-	ResourceTable_test.cpp \
-	ResourceUtils_test.cpp \
-	SdkConstants_test.cpp \
-	StringPool_test.cpp \
-	ValueVisitor_test.cpp \
-	xml/XmlActionExecutor_test.cpp \
-	xml/XmlDom_test.cpp \
-	xml/XmlPullParser_test.cpp \
-	xml/XmlUtil_test.cpp
-
-toolSources := \
-	compile/Compile.cpp \
-	diff/Diff.cpp \
-	dump/Dump.cpp \
-	link/Link.cpp
-
-hostLdLibs :=
-
-hostStaticLibs := \
-	libandroidfw \
-	libutils \
-	liblog \
-	libcutils \
-	libexpat \
-	libziparchive \
-	libpng \
-	libbase \
-	libprotobuf-cpp-lite
-
-
-# Statically link libz for MinGW (Win SDK under Linux),
-# and dynamically link for all others.
-hostStaticLibs_windows := libz
-hostLdLibs_linux := -lz
-hostLdLibs_darwin := -lz
-
-cFlags := -Wall -Werror -Wno-unused-parameter
-cFlags_darwin := -D_DARWIN_UNLIMITED_STREAMS
-cFlags_windows := -Wno-maybe-uninitialized # Incorrectly marking use of Maybe.value() as error.
-cppFlags := -Wno-missing-field-initializers -fno-exceptions -fno-rtti
-protoIncludes := $(call generated-sources-dir-for,STATIC_LIBRARIES,libaapt2,HOST)
-
-# ==========================================================
-# NOTE: Do not add any shared libraries.
-# AAPT2 is built to run on many environments
-# that may not have the required dependencies.
-# ==========================================================
-
-# ==========================================================
-# Build the host static library: libaapt2
-# ==========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := libaapt2
-LOCAL_MODULE_CLASS := STATIC_LIBRARIES
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := $(cFlags)
-LOCAL_CFLAGS_darwin := $(cFlags_darwin)
-LOCAL_CFLAGS_windows := $(cFlags_windows)
-LOCAL_CPPFLAGS := $(cppFlags)
-LOCAL_C_INCLUDES := $(protoIncludes)
-LOCAL_SRC_FILES := $(sources)
-LOCAL_STATIC_LIBRARIES := $(hostStaticLibs)
-LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
-include $(BUILD_HOST_STATIC_LIBRARY)
-
-
-# ==========================================================
-# Build the host shared library: libaapt2_jni
-# ==========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := libaapt2_jni
-LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := $(cFlags)
-LOCAL_CFLAGS_darwin := $(cFlags_darwin)
-LOCAL_CFLAGS_windows := $(cFlags_windows)
-LOCAL_CPPFLAGS := $(cppFlags)
-LOCAL_C_INCLUDES := $(protoIncludes)
-LOCAL_SRC_FILES := $(toolSources) $(sourcesJni)
-LOCAL_STATIC_LIBRARIES := libaapt2 $(hostStaticLibs)
-LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
-LOCAL_LDLIBS := $(hostLdLibs)
-LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
-LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
-include $(BUILD_HOST_SHARED_LIBRARY)
-
-
-# ==========================================================
-# Build the host tests: libaapt2_tests
-# ==========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := libaapt2_tests
-LOCAL_MODULE_TAGS := tests
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := $(cFlags)
-LOCAL_CFLAGS_darwin := $(cFlags_darwin)
-LOCAL_CFLAGS_windows := $(cFlags_windows)
-LOCAL_CPPFLAGS := $(cppFlags)
-LOCAL_C_INCLUDES := $(protoIncludes)
-LOCAL_SRC_FILES := $(testSources)
-LOCAL_STATIC_LIBRARIES := libaapt2 $(hostStaticLibs)
-LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
-LOCAL_LDLIBS := $(hostLdLibs)
-LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
-LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
-include $(BUILD_HOST_NATIVE_TEST)
-
-# ==========================================================
-# Build the host executable: aapt2
-# ==========================================================
-include $(CLEAR_VARS)
-LOCAL_MODULE := aapt2
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_CFLAGS := $(cFlags)
-LOCAL_CFLAGS_darwin := $(cFlags_darwin)
-LOCAL_CFLAGS_windows := $(cFlags_windows)
-LOCAL_CPPFLAGS := $(cppFlags)
-LOCAL_C_INCLUDES := $(protoIncludes)
-LOCAL_SRC_FILES := $(main) $(toolSources)
-LOCAL_STATIC_LIBRARIES := libaapt2 $(hostStaticLibs)
-LOCAL_STATIC_LIBRARIES_windows := $(hostStaticLibs_windows)
-LOCAL_LDLIBS := $(hostLdLibs)
-LOCAL_LDLIBS_darwin := $(hostLdLibs_darwin)
-LOCAL_LDLIBS_linux := $(hostLdLibs_linux)
-include $(BUILD_HOST_EXECUTABLE)
-
-ifeq ($(ONE_SHOT_MAKEFILE),)
-include $(call all-makefiles-under,$(LOCAL_PATH))
-endif
diff --git a/tools/aapt2/proto/ProtoHelpers.h b/tools/aapt2/proto/ProtoHelpers.h
index 735cda0..344e947 100644
--- a/tools/aapt2/proto/ProtoHelpers.h
+++ b/tools/aapt2/proto/ProtoHelpers.h
@@ -23,7 +23,7 @@
 #include "ResourceTable.h"
 #include "Source.h"
 #include "StringPool.h"
-#include "proto/frameworks/base/tools/aapt2/Format.pb.h"
+#include "Format.pb.h"
 
 namespace aapt {
 
diff --git a/tools/localedata/extract_icu_data.py b/tools/localedata/extract_icu_data.py
index b071093..9dceba2 100755
--- a/tools/localedata/extract_icu_data.py
+++ b/tools/localedata/extract_icu_data.py
@@ -48,6 +48,8 @@
             # they may be used by apps for other purposes.)
             "en_XA": "~~~A",
             "ar_XB": "~~~B",
+            # Removed data from later versions of ICU
+            "ji": "Hebr", # Old code for Yiddish, still used in Java and Android
         }
         representative_locales = {
             # Android's additions
@@ -69,7 +71,7 @@
                 _, to_scr, to_region = get_locale_parts(to_locale)
                 if from_lang == 'und':
                     continue  # not very useful for our purposes
-                if from_region is None and to_region != '001':
+                if from_region is None and to_region not in ['001', 'ZZ']:
                     representative_locales.add(to_locale)
                 if from_scr is None:
                     likely_script_dict[from_locale] = to_scr
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 958279b..3a45671 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -22,6 +22,7 @@
 import android.net.IpConfiguration.ProxySettings;
 import android.net.ProxyInfo;
 import android.net.StaticIpConfiguration;
+import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.UserHandle;
@@ -1805,14 +1806,48 @@
         mIpConfiguration.proxySettings = proxySettings;
     }
 
-    /** @hide */
+    /**
+     * Returns the HTTP proxy used by this object.
+     * @return a {@link ProxyInfo httpProxy} representing the proxy specified by this
+     *                  WifiConfiguration, or {@code null} if no proxy is specified.
+     */
     public ProxyInfo getHttpProxy() {
-        return mIpConfiguration.httpProxy;
+        if (mIpConfiguration.proxySettings == IpConfiguration.ProxySettings.NONE) {
+            return null;
+        }
+        return new ProxyInfo(mIpConfiguration.httpProxy);
     }
 
-    /** @hide */
+    /**
+     * Set the {@link ProxyInfo} for this WifiConfiguration.
+     * @param httpProxy {@link ProxyInfo} representing the httpProxy to be used by this
+     *                  WifiConfiguration. Setting this {@code null} will explicitly set no proxy,
+     *                  removing any proxy that was previously set.
+     * @exception throw IllegalArgumentException for invalid httpProxy
+     */
     public void setHttpProxy(ProxyInfo httpProxy) {
-        mIpConfiguration.httpProxy = httpProxy;
+        if (httpProxy == null) {
+            mIpConfiguration.setProxySettings(IpConfiguration.ProxySettings.NONE);
+            mIpConfiguration.setHttpProxy(null);
+            return;
+        }
+        ProxyInfo httpProxyCopy;
+        ProxySettings proxySettingCopy;
+        if (!Uri.EMPTY.equals(httpProxy.getPacFileUrl())) {
+            proxySettingCopy = IpConfiguration.ProxySettings.PAC;
+            // Construct a new PAC URL Proxy
+            httpProxyCopy = new ProxyInfo(httpProxy.getPacFileUrl(), httpProxy.getPort());
+        } else {
+            proxySettingCopy = IpConfiguration.ProxySettings.STATIC;
+            // Construct a new HTTP Proxy
+            httpProxyCopy = new ProxyInfo(httpProxy.getHost(), httpProxy.getPort(),
+                    httpProxy.getExclusionListAsString());
+        }
+        if (!httpProxyCopy.isValid()) {
+            throw new IllegalArgumentException("Invalid ProxyInfo: " + httpProxyCopy.toString());
+        }
+        mIpConfiguration.setProxySettings(proxySettingCopy);
+        mIpConfiguration.setHttpProxy(httpProxyCopy);
     }
 
     /** @hide */
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 88820cd..3b6e76f 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -791,6 +791,8 @@
      *
      * @param config the set of variables that describe the configuration,
      *            contained in a {@link WifiConfiguration} object.
+     *            If the {@link WifiConfiguration} has an Http Proxy set
+     *            the calling app must be System, or be provisioned as the Profile or Device Owner.
      * @return the ID of the newly created network description. This is used in
      *         other operations to specified the network to be acted upon.
      *         Returns {@code -1} on failure.
@@ -811,6 +813,8 @@
      *            be sparse, so that only the items that are being changed
      *            are non-<code>null</code>. The {@code networkId} field
      *            must be set to the ID of the existing network being updated.
+     *            If the {@link WifiConfiguration} has an Http Proxy set
+     *            the calling app must be System, or be provisioned as the Profile or Device Owner.
      * @return Returns the {@code networkId} of the supplied
      *         {@code WifiConfiguration} on success.
      *         <br/>
@@ -1075,7 +1079,6 @@
         }
     }
 
-    /* Keep this list in sync with wifi_hal.h */
     /** @hide */
     public static final int WIFI_FEATURE_INFRA            = 0x0001;  // Basic infrastructure mode
     /** @hide */
@@ -1089,7 +1092,7 @@
     /** @hide */
     public static final int WIFI_FEATURE_SCANNER          = 0x0020;  // WifiScanner APIs
     /** @hide */
-    public static final int WIFI_FEATURE_AWARE              = 0x0040;  // Wi-Fi AWare networking
+    public static final int WIFI_FEATURE_AWARE            = 0x0040;  // Wi-Fi AWare networking
     /** @hide */
     public static final int WIFI_FEATURE_D2D_RTT          = 0x0080;  // Device-to-device RTT
     /** @hide */
@@ -1107,13 +1110,28 @@
     /** @hide */
     public static final int WIFI_FEATURE_EPR              = 0x4000;  // Enhanced power reporting
     /** @hide */
-    public static final int WIFI_FEATURE_AP_STA            = 0x8000;  // Support for AP STA Concurrency
+    public static final int WIFI_FEATURE_AP_STA           = 0x8000;  // AP STA Concurrency
     /** @hide */
-    public static final int WIFI_FEATURE_LINK_LAYER_STATS  = 0x10000; // Link layer stats collection
+    public static final int WIFI_FEATURE_LINK_LAYER_STATS = 0x10000; // Link layer stats collection
     /** @hide */
-    public static final int WIFI_FEATURE_LOGGER            = 0x20000; // WiFi Logger
+    public static final int WIFI_FEATURE_LOGGER           = 0x20000; // WiFi Logger
     /** @hide */
-    public static final int WIFI_FEATURE_HAL_EPNO          = 0x40000; // WiFi PNO enhanced
+    public static final int WIFI_FEATURE_HAL_EPNO         = 0x40000; // Enhanced PNO
+    /** @hide */
+    public static final int WIFI_FEATURE_RSSI_MONITOR     = 0x80000; // RSSI Monitor
+    /** @hide */
+    public static final int WIFI_FEATURE_MKEEP_ALIVE      = 0x100000; // mkeep_alive
+    /** @hide */
+    public static final int WIFI_FEATURE_CONFIG_NDO       = 0x200000; // ND offload
+    /** @hide */
+    public static final int WIFI_FEATURE_TRANSMIT_POWER   = 0x400000; // Capture transmit power
+    /** @hide */
+    public static final int WIFI_FEATURE_CONTROL_ROAMING  = 0x800000; // Control firmware roaming
+    /** @hide */
+    public static final int WIFI_FEATURE_IE_WHITELIST     = 0x1000000; // Probe IE white listing
+    /** @hide */
+    public static final int WIFI_FEATURE_SCAN_RAND        = 0x2000000; // Random MAC & Probe seq
+
 
     private int getSupportedFeatures() {
         try {